// Code generated by protoc-gen-ts-client. DO NOT EDIT.
// source: worldmonitor/news/v1/service.proto

export interface SummarizeArticleRequest {
  provider: string;
  headlines: string[];
  mode: string;
  geoContext: string;
  variant: string;
  lang: string;
  systemAppend: string;
}

export interface SummarizeArticleResponse {
  summary: string;
  model: string;
  provider: string;
  tokens: number;
  fallback: boolean;
  error: string;
  errorType: string;
  status: SummarizeStatus;
  statusDetail: string;
}

export interface GetSummarizeArticleCacheRequest {
  cacheKey: string;
}

export interface ListFeedDigestRequest {
  variant: string;
  lang: string;
}

export interface ListFeedDigestResponse {
  categories: Record<string, CategoryBucket>;
  feedStatuses: Record<string, string>;
  generatedAt: string;
}

export interface CategoryBucket {
  items: NewsItem[];
}

export interface NewsItem {
  source: string;
  title: string;
  link: string;
  publishedAt: number;
  isAlert: boolean;
  threat?: ThreatClassification;
  location?: GeoCoordinates;
  locationName: string;
  importanceScore: number;
  corroborationCount: number;
  storyMeta?: StoryMeta;
}

export interface ThreatClassification {
  level: ThreatLevel;
  category: string;
  confidence: number;
  source: string;
}

export interface GeoCoordinates {
  latitude: number;
  longitude: number;
}

export interface StoryMeta {
  firstSeen: number;
  mentionCount: number;
  sourceCount: number;
  phase: StoryPhase;
}

export type StoryPhase = "STORY_PHASE_UNSPECIFIED" | "STORY_PHASE_BREAKING" | "STORY_PHASE_DEVELOPING" | "STORY_PHASE_SUSTAINED" | "STORY_PHASE_FADING";

export type SummarizeStatus = "SUMMARIZE_STATUS_UNSPECIFIED" | "SUMMARIZE_STATUS_SUCCESS" | "SUMMARIZE_STATUS_CACHED" | "SUMMARIZE_STATUS_SKIPPED" | "SUMMARIZE_STATUS_ERROR";

export type ThreatLevel = "THREAT_LEVEL_UNSPECIFIED" | "THREAT_LEVEL_LOW" | "THREAT_LEVEL_MEDIUM" | "THREAT_LEVEL_HIGH" | "THREAT_LEVEL_CRITICAL";

export interface FieldViolation {
  field: string;
  description: string;
}

export class ValidationError extends Error {
  violations: FieldViolation[];

  constructor(violations: FieldViolation[]) {
    super("Validation failed");
    this.name = "ValidationError";
    this.violations = violations;
  }
}

export class ApiError extends Error {
  statusCode: number;
  body: string;

  constructor(statusCode: number, message: string, body: string) {
    super(message);
    this.name = "ApiError";
    this.statusCode = statusCode;
    this.body = body;
  }
}

export interface NewsServiceClientOptions {
  fetch?: typeof fetch;
  defaultHeaders?: Record<string, string>;
}

export interface NewsServiceCallOptions {
  headers?: Record<string, string>;
  signal?: AbortSignal;
}

export class NewsServiceClient {
  private baseURL: string;
  private fetchFn: typeof fetch;
  private defaultHeaders: Record<string, string>;

  constructor(baseURL: string, options?: NewsServiceClientOptions) {
    this.baseURL = baseURL.replace(/\/+$/, "");
    this.fetchFn = options?.fetch ?? globalThis.fetch;
    this.defaultHeaders = { ...options?.defaultHeaders };
  }

  async summarizeArticle(req: SummarizeArticleRequest, options?: NewsServiceCallOptions): Promise<SummarizeArticleResponse> {
    let path = "/api/news/v1/summarize-article";
    const url = this.baseURL + path;

    const headers: Record<string, string> = {
      "Content-Type": "application/json",
      ...this.defaultHeaders,
      ...options?.headers,
    };

    const resp = await this.fetchFn(url, {
      method: "POST",
      headers,
      body: JSON.stringify(req),
      signal: options?.signal,
    });

    if (!resp.ok) {
      return this.handleError(resp);
    }

    return await resp.json() as SummarizeArticleResponse;
  }

  async getSummarizeArticleCache(req: GetSummarizeArticleCacheRequest, options?: NewsServiceCallOptions): Promise<SummarizeArticleResponse> {
    let path = "/api/news/v1/summarize-article-cache";
    const params = new URLSearchParams();
    if (req.cacheKey != null && req.cacheKey !== "") params.set("cache_key", String(req.cacheKey));
    const url = this.baseURL + path + (params.toString() ? "?" + params.toString() : "");

    const headers: Record<string, string> = {
      "Content-Type": "application/json",
      ...this.defaultHeaders,
      ...options?.headers,
    };

    const resp = await this.fetchFn(url, {
      method: "GET",
      headers,
      signal: options?.signal,
    });

    if (!resp.ok) {
      return this.handleError(resp);
    }

    return await resp.json() as SummarizeArticleResponse;
  }

  async listFeedDigest(req: ListFeedDigestRequest, options?: NewsServiceCallOptions): Promise<ListFeedDigestResponse> {
    let path = "/api/news/v1/list-feed-digest";
    const params = new URLSearchParams();
    if (req.variant != null && req.variant !== "") params.set("variant", String(req.variant));
    if (req.lang != null && req.lang !== "") params.set("lang", String(req.lang));
    const url = this.baseURL + path + (params.toString() ? "?" + params.toString() : "");

    const headers: Record<string, string> = {
      "Content-Type": "application/json",
      ...this.defaultHeaders,
      ...options?.headers,
    };

    const resp = await this.fetchFn(url, {
      method: "GET",
      headers,
      signal: options?.signal,
    });

    if (!resp.ok) {
      return this.handleError(resp);
    }

    return await resp.json() as ListFeedDigestResponse;
  }

  private async handleError(resp: Response): Promise<never> {
    const body = await resp.text();
    if (resp.status === 400) {
      try {
        const parsed = JSON.parse(body);
        if (parsed.violations) {
          throw new ValidationError(parsed.violations);
        }
      } catch (e) {
        if (e instanceof ValidationError) throw e;
      }
    }
    throw new ApiError(resp.status, `Request failed with status ${resp.status}`, body);
  }
}

