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

export interface ListInternetOutagesRequest {
  start: number;
  end: number;
  pageSize: number;
  cursor: string;
  country: string;
}

export interface ListInternetOutagesResponse {
  outages: InternetOutage[];
  pagination?: PaginationResponse;
}

export interface InternetOutage {
  id: string;
  title: string;
  link: string;
  description: string;
  detectedAt: number;
  country: string;
  region: string;
  location?: GeoCoordinates;
  severity: OutageSeverity;
  categories: string[];
  cause: string;
  outageType: string;
  endedAt: number;
}

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

export interface PaginationResponse {
  nextCursor: string;
  totalCount: number;
}

export interface ListServiceStatusesRequest {
  status: ServiceOperationalStatus;
}

export interface ListServiceStatusesResponse {
  statuses: ServiceStatus[];
}

export interface ServiceStatus {
  id: string;
  name: string;
  status: ServiceOperationalStatus;
  description: string;
  url: string;
  checkedAt: number;
  latencyMs: number;
}

export interface GetTemporalBaselineRequest {
  type: string;
  region: string;
  count: number;
}

export interface GetTemporalBaselineResponse {
  anomaly?: BaselineAnomaly;
  baseline?: BaselineStats;
  learning: boolean;
  sampleCount: number;
  samplesNeeded: number;
  error: string;
}

export interface BaselineAnomaly {
  zScore: number;
  severity: string;
  multiplier: number;
}

export interface BaselineStats {
  mean: number;
  stdDev: number;
  sampleCount: number;
}

export interface GetIpGeoRequest {
}

export interface GetIpGeoResponse {
  country: string;
  region: string;
  city: string;
}

export interface ReverseGeocodeRequest {
  lat: number;
  lon: number;
}

export interface ReverseGeocodeResponse {
  country: string;
  code: string;
  displayName: string;
  error: string;
}

export interface GetBootstrapDataRequest {
  tier: string;
  keys: string[];
}

export interface GetBootstrapDataResponse {
  data: Record<string, string>;
  missing: string[];
}

export interface RecordBaselineSnapshotRequest {
  updates: BaselineUpdate[];
}

export interface BaselineUpdate {
  type: string;
  region: string;
  count: number;
}

export interface RecordBaselineSnapshotResponse {
  updated: number;
  error: string;
}

export interface GetCableHealthRequest {
}

export interface GetCableHealthResponse {
  generatedAt: number;
  cables: Record<string, CableHealthRecord>;
}

export interface CableHealthRecord {
  status: CableHealthStatus;
  score: number;
  confidence: number;
  lastUpdated: number;
  evidence: CableHealthEvidence[];
}

export interface CableHealthEvidence {
  source: string;
  summary: string;
  ts: number;
}

export interface ListTemporalAnomaliesRequest {
}

export interface ListTemporalAnomaliesResponse {
  anomalies: TemporalAnomaly[];
  trackedTypes: string[];
  computedAt: string;
}

export interface TemporalAnomaly {
  type: string;
  region: string;
  currentCount: number;
  expectedCount: number;
  zScore: number;
  severity: string;
  multiplier: number;
  message: string;
}

export interface ListInternetDdosAttacksRequest {
}

export interface ListInternetDdosAttacksResponse {
  protocol: DdosAttackSummaryEntry[];
  vector: DdosAttackSummaryEntry[];
  dateRangeStart: string;
  dateRangeEnd: string;
  topTargetLocations: DdosLocationHit[];
}

export interface DdosAttackSummaryEntry {
  label: string;
  percentage: number;
}

export interface DdosLocationHit {
  countryCode: string;
  countryName: string;
  percentage: number;
  latitude: number;
  longitude: number;
}

export interface ListInternetTrafficAnomaliesRequest {
  country: string;
}

export interface ListInternetTrafficAnomaliesResponse {
  anomalies: TrafficAnomaly[];
  totalCount: number;
}

export interface TrafficAnomaly {
  uuid: string;
  type: string;
  status: string;
  startDate: number;
  endDate: number;
  asn: string;
  asnName: string;
  locationCode: string;
  locationName: string;
  latitude: number;
  longitude: number;
}

export type CableHealthStatus = "CABLE_HEALTH_STATUS_UNSPECIFIED" | "CABLE_HEALTH_STATUS_OK" | "CABLE_HEALTH_STATUS_DEGRADED" | "CABLE_HEALTH_STATUS_FAULT";

export type OutageSeverity = "OUTAGE_SEVERITY_UNSPECIFIED" | "OUTAGE_SEVERITY_PARTIAL" | "OUTAGE_SEVERITY_MAJOR" | "OUTAGE_SEVERITY_TOTAL";

export type ServiceOperationalStatus = "SERVICE_OPERATIONAL_STATUS_UNSPECIFIED" | "SERVICE_OPERATIONAL_STATUS_OPERATIONAL" | "SERVICE_OPERATIONAL_STATUS_DEGRADED" | "SERVICE_OPERATIONAL_STATUS_PARTIAL_OUTAGE" | "SERVICE_OPERATIONAL_STATUS_MAJOR_OUTAGE" | "SERVICE_OPERATIONAL_STATUS_MAINTENANCE";

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 InfrastructureServiceClientOptions {
  fetch?: typeof fetch;
  defaultHeaders?: Record<string, string>;
}

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

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

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

  async listInternetOutages(req: ListInternetOutagesRequest, options?: InfrastructureServiceCallOptions): Promise<ListInternetOutagesResponse> {
    let path = "/api/infrastructure/v1/list-internet-outages";
    const params = new URLSearchParams();
    if (req.start != null && req.start !== 0) params.set("start", String(req.start));
    if (req.end != null && req.end !== 0) params.set("end", String(req.end));
    if (req.pageSize != null && req.pageSize !== 0) params.set("page_size", String(req.pageSize));
    if (req.cursor != null && req.cursor !== "") params.set("cursor", String(req.cursor));
    if (req.country != null && req.country !== "") params.set("country", String(req.country));
    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 ListInternetOutagesResponse;
  }

  async listServiceStatuses(req: ListServiceStatusesRequest, options?: InfrastructureServiceCallOptions): Promise<ListServiceStatusesResponse> {
    let path = "/api/infrastructure/v1/list-service-statuses";
    const params = new URLSearchParams();
    if (req.status != null && req.status !== "SERVICE_OPERATIONAL_STATUS_UNSPECIFIED") params.set("status", String(req.status));
    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 ListServiceStatusesResponse;
  }

  async getTemporalBaseline(req: GetTemporalBaselineRequest, options?: InfrastructureServiceCallOptions): Promise<GetTemporalBaselineResponse> {
    let path = "/api/infrastructure/v1/get-temporal-baseline";
    const params = new URLSearchParams();
    if (req.type != null && req.type !== "") params.set("type", String(req.type));
    if (req.region != null && req.region !== "") params.set("region", String(req.region));
    if (req.count != null && req.count !== 0) params.set("count", String(req.count));
    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 GetTemporalBaselineResponse;
  }

  async getIpGeo(_req: GetIpGeoRequest, options?: InfrastructureServiceCallOptions): Promise<GetIpGeoResponse> {
    let path = "/api/infrastructure/v1/get-ip-geo";
    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: "GET",
      headers,
      signal: options?.signal,
    });

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

    return await resp.json() as GetIpGeoResponse;
  }

  async reverseGeocode(req: ReverseGeocodeRequest, options?: InfrastructureServiceCallOptions): Promise<ReverseGeocodeResponse> {
    let path = "/api/infrastructure/v1/reverse-geocode";
    const params = new URLSearchParams();
    if (req.lat != null && req.lat !== 0) params.set("lat", String(req.lat));
    if (req.lon != null && req.lon !== 0) params.set("lon", String(req.lon));
    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 ReverseGeocodeResponse;
  }

  async getBootstrapData(req: GetBootstrapDataRequest, options?: InfrastructureServiceCallOptions): Promise<GetBootstrapDataResponse> {
    let path = "/api/infrastructure/v1/get-bootstrap-data";
    const params = new URLSearchParams();
    if (req.tier != null && req.tier !== "") params.set("tier", String(req.tier));
    if (req.keys && req.keys.length > 0) req.keys.forEach(v => params.append("keys", v));
    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 GetBootstrapDataResponse;
  }

  async recordBaselineSnapshot(req: RecordBaselineSnapshotRequest, options?: InfrastructureServiceCallOptions): Promise<RecordBaselineSnapshotResponse> {
    let path = "/api/infrastructure/v1/record-baseline-snapshot";
    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 RecordBaselineSnapshotResponse;
  }

  async getCableHealth(_req: GetCableHealthRequest, options?: InfrastructureServiceCallOptions): Promise<GetCableHealthResponse> {
    let path = "/api/infrastructure/v1/get-cable-health";
    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: "GET",
      headers,
      signal: options?.signal,
    });

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

    return await resp.json() as GetCableHealthResponse;
  }

  async listTemporalAnomalies(_req: ListTemporalAnomaliesRequest, options?: InfrastructureServiceCallOptions): Promise<ListTemporalAnomaliesResponse> {
    let path = "/api/infrastructure/v1/list-temporal-anomalies";
    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: "GET",
      headers,
      signal: options?.signal,
    });

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

    return await resp.json() as ListTemporalAnomaliesResponse;
  }

  async listInternetDdosAttacks(_req: ListInternetDdosAttacksRequest, options?: InfrastructureServiceCallOptions): Promise<ListInternetDdosAttacksResponse> {
    let path = "/api/infrastructure/v1/list-internet-ddos-attacks";
    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: "GET",
      headers,
      signal: options?.signal,
    });

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

    return await resp.json() as ListInternetDdosAttacksResponse;
  }

  async listInternetTrafficAnomalies(req: ListInternetTrafficAnomaliesRequest, options?: InfrastructureServiceCallOptions): Promise<ListInternetTrafficAnomaliesResponse> {
    let path = "/api/infrastructure/v1/list-internet-traffic-anomalies";
    const params = new URLSearchParams();
    if (req.country != null && req.country !== "") params.set("country", String(req.country));
    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 ListInternetTrafficAnomaliesResponse;
  }

  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);
  }
}

