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

export interface GetShippingRatesRequest {
}

export interface GetShippingRatesResponse {
  indices: ShippingIndex[];
  fetchedAt: string;
  upstreamUnavailable: boolean;
}

export interface ShippingIndex {
  indexId: string;
  name: string;
  currentValue: number;
  previousValue: number;
  changePct: number;
  unit: string;
  history: ShippingRatePoint[];
  spikeAlert: boolean;
}

export interface ShippingRatePoint {
  date: string;
  value: number;
}

export interface GetChokepointStatusRequest {
}

export interface GetChokepointStatusResponse {
  chokepoints: ChokepointInfo[];
  fetchedAt: string;
  upstreamUnavailable: boolean;
}

export interface ChokepointInfo {
  id: string;
  name: string;
  lat: number;
  lon: number;
  disruptionScore: number;
  status: string;
  activeWarnings: number;
  congestionLevel: string;
  affectedRoutes: string[];
  description: string;
  aisDisruptions: number;
  directions: string[];
  directionalDwt: DirectionalDwt[];
  transitSummary?: TransitSummary;
  flowEstimate?: FlowEstimate;
  warRiskTier: WarRiskTier;
}

export interface DirectionalDwt {
  direction: string;
  dwtThousandTonnes: number;
  wowChangePct: number;
}

export interface TransitSummary {
  todayTotal: number;
  todayTanker: number;
  todayCargo: number;
  todayOther: number;
  wowChangePct: number;
  history: TransitDayCount[];
  riskLevel: string;
  incidentCount7d: number;
  disruptionPct: number;
  riskSummary: string;
  riskReportAction: string;
  dataAvailable: boolean;
}

export interface TransitDayCount {
  date: string;
  tanker: number;
  cargo: number;
  other: number;
  total: number;
  container: number;
  dryBulk: number;
  generalCargo: number;
  roro: number;
  capContainer: number;
  capDryBulk: number;
  capGeneralCargo: number;
  capRoro: number;
  capTanker: number;
}

export interface FlowEstimate {
  currentMbd: number;
  baselineMbd: number;
  flowRatio: number;
  disrupted: boolean;
  source: string;
  hazardAlertLevel: string;
  hazardAlertName: string;
}

export interface GetChokepointHistoryRequest {
  chokepointId: string;
}

export interface GetChokepointHistoryResponse {
  chokepointId: string;
  history: TransitDayCount[];
  fetchedAt: string;
}

export interface GetCriticalMineralsRequest {
}

export interface GetCriticalMineralsResponse {
  minerals: CriticalMineral[];
  fetchedAt: string;
  upstreamUnavailable: boolean;
}

export interface CriticalMineral {
  mineral: string;
  topProducers: MineralProducer[];
  hhi: number;
  riskRating: string;
  globalProduction: number;
  unit: string;
}

export interface MineralProducer {
  country: string;
  countryCode: string;
  productionTonnes: number;
  sharePct: number;
}

export interface GetShippingStressRequest {
}

export interface GetShippingStressResponse {
  carriers: ShippingStressCarrier[];
  stressScore: number;
  stressLevel: string;
  fetchedAt: number;
  upstreamUnavailable: boolean;
}

export interface ShippingStressCarrier {
  symbol: string;
  name: string;
  price: number;
  changePct: number;
  carrierType: string;
  sparkline: number[];
}

export interface GetCountryChokepointIndexRequest {
  iso2: string;
  hs2: string;
}

export interface GetCountryChokepointIndexResponse {
  iso2: string;
  hs2: string;
  exposures: ChokepointExposureEntry[];
  primaryChokepointId: string;
  vulnerabilityIndex: number;
  fetchedAt: string;
}

export interface ChokepointExposureEntry {
  chokepointId: string;
  chokepointName: string;
  exposureScore: number;
  coastSide: string;
  shockSupported: boolean;
}

export interface GetBypassOptionsRequest {
  chokepointId: string;
  cargoType: string;
  closurePct: number;
}

export interface GetBypassOptionsResponse {
  chokepointId: string;
  cargoType: string;
  closurePct: number;
  options: BypassOption[];
  fetchedAt: string;
  primaryChokepointWarRiskTier: WarRiskTier;
}

export interface BypassOption {
  id: string;
  name: string;
  type: string;
  addedTransitDays: number;
  addedCostMultiplier: number;
  capacityConstraintTonnage: string;
  suitableCargoTypes: string[];
  activationThreshold: string;
  waypointChokepointIds: string[];
  liveScore: number;
  bypassWarRiskTier: WarRiskTier;
  notes: string;
}

export interface GetCountryCostShockRequest {
  iso2: string;
  chokepointId: string;
  hs2: string;
}

export interface GetCountryCostShockResponse {
  iso2: string;
  chokepointId: string;
  hs2: string;
  supplyDeficitPct: number;
  coverageDays: number;
  warRiskPremiumBps: number;
  warRiskTier: WarRiskTier;
  hasEnergyModel: boolean;
  unavailableReason: string;
  fetchedAt: string;
}

export interface GetCountryProductsRequest {
  iso2: string;
}

export interface GetCountryProductsResponse {
  iso2: string;
  products: CountryProduct[];
  fetchedAt: string;
}

export interface CountryProduct {
  hs4: string;
  description: string;
  totalValue: number;
  topExporters: ProductExporter[];
  year: number;
}

export interface ProductExporter {
  partnerCode: number;
  partnerIso2: string;
  value: number;
  share: number;
}

export interface GetMultiSectorCostShockRequest {
  iso2: string;
  chokepointId: string;
  closureDays: number;
}

export interface GetMultiSectorCostShockResponse {
  iso2: string;
  chokepointId: string;
  closureDays: number;
  warRiskTier: WarRiskTier;
  sectors: MultiSectorCostShock[];
  totalAddedCost: number;
  fetchedAt: string;
  unavailableReason: string;
}

export interface MultiSectorCostShock {
  hs2: string;
  hs2Label: string;
  importValueAnnual: number;
  freightAddedPctPerTon: number;
  warRiskPremiumBps: number;
  addedTransitDays: number;
  totalCostShockPerDay: number;
  totalCostShock30Days: number;
  totalCostShock90Days: number;
  totalCostShock: number;
  closureDays: number;
}

export interface GetSectorDependencyRequest {
  iso2: string;
  hs2: string;
}

export interface GetSectorDependencyResponse {
  iso2: string;
  hs2: string;
  hs2Label: string;
  flags: DependencyFlag[];
  primaryExporterIso2: string;
  primaryExporterShare: number;
  primaryChokepointId: string;
  primaryChokepointExposure: number;
  hasViableBypass: boolean;
  fetchedAt: string;
}

export interface GetRouteExplorerLaneRequest {
  fromIso2: string;
  toIso2: string;
  hs2: string;
  cargoType: string;
}

export interface GetRouteExplorerLaneResponse {
  fromIso2: string;
  toIso2: string;
  hs2: string;
  cargoType: string;
  primaryRouteId: string;
  primaryRouteGeometry: GeoPoint[];
  chokepointExposures: ChokepointExposureSummary[];
  bypassOptions: BypassCorridorOption[];
  warRiskTier: string;
  disruptionScore: number;
  estTransitDaysRange?: NumberRange;
  estFreightUsdPerTeuRange?: NumberRange;
  noModeledLane: boolean;
  fetchedAt: string;
}

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

export interface ChokepointExposureSummary {
  chokepointId: string;
  chokepointName: string;
  exposurePct: number;
}

export interface BypassCorridorOption {
  id: string;
  name: string;
  type: string;
  addedTransitDays: number;
  addedCostMultiplier: number;
  warRiskTier: string;
  status: CorridorStatus;
  fromPort?: GeoPoint;
  toPort?: GeoPoint;
}

export interface NumberRange {
  min: number;
  max: number;
}

export interface GetRouteImpactRequest {
  fromIso2: string;
  toIso2: string;
  hs2: string;
}

export interface GetRouteImpactResponse {
  laneValueUsd: number;
  primaryExporterIso2: string;
  primaryExporterShare: number;
  topStrategicProducts: StrategicProduct[];
  resilienceScore: number;
  dependencyFlags: DependencyFlag[];
  hs2InSeededUniverse: boolean;
  comtradeSource: string;
  fetchedAt: string;
}

export interface StrategicProduct {
  hs4: string;
  label: string;
  totalValueUsd: number;
  topExporterIso2: string;
  topExporterShare: number;
  primaryChokepointId: string;
}

export interface ListPipelinesRequest {
  commodityType: string;
}

export interface ListPipelinesResponse {
  pipelines: PipelineEntry[];
  fetchedAt: string;
  classifierVersion: string;
  upstreamUnavailable: boolean;
}

export interface PipelineEntry {
  id: string;
  name: string;
  operator: string;
  commodityType: string;
  fromCountry: string;
  toCountry: string;
  transitCountries: string[];
  capacityBcmYr: number;
  capacityMbd: number;
  lengthKm: number;
  inService: number;
  startPoint?: LatLon;
  endPoint?: LatLon;
  waypoints: LatLon[];
  evidence?: PipelineEvidence;
  publicBadge: string;
}

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

export interface PipelineEvidence {
  physicalState: string;
  physicalStateSource: string;
  operatorStatement?: OperatorStatement;
  commercialState: string;
  sanctionRefs: SanctionRef[];
  lastEvidenceUpdate: string;
  classifierVersion: string;
  classifierConfidence: number;
}

export interface OperatorStatement {
  text: string;
  url: string;
  date: string;
}

export interface SanctionRef {
  authority: string;
  listId: string;
  date: string;
  url: string;
}

export interface GetPipelineDetailRequest {
  pipelineId: string;
}

export interface GetPipelineDetailResponse {
  pipeline?: PipelineEntry;
  revisions: PipelineRevisionEntry[];
  fetchedAt: string;
  unavailable: boolean;
}

export interface PipelineRevisionEntry {
  date: string;
  fieldChanged: string;
  previousValue: string;
  newValue: string;
  trigger: string;
  sourcesUsed: string[];
  classifierVersion: string;
}

export interface ListStorageFacilitiesRequest {
  facilityType: string;
}

export interface ListStorageFacilitiesResponse {
  facilities: StorageFacilityEntry[];
  fetchedAt: string;
  classifierVersion: string;
  upstreamUnavailable: boolean;
}

export interface StorageFacilityEntry {
  id: string;
  name: string;
  operator: string;
  facilityType: string;
  country: string;
  location?: StorageLatLon;
  capacityTwh: number;
  capacityMb: number;
  capacityMtpa: number;
  workingCapacityUnit: string;
  inService: number;
  evidence?: StorageEvidence;
  publicBadge: string;
}

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

export interface StorageEvidence {
  physicalState: string;
  physicalStateSource: string;
  operatorStatement?: StorageOperatorStatement;
  commercialState: string;
  sanctionRefs: StorageSanctionRef[];
  fillDisclosed: boolean;
  fillSource: string;
  lastEvidenceUpdate: string;
  classifierVersion: string;
  classifierConfidence: number;
}

export interface StorageOperatorStatement {
  text: string;
  url: string;
  date: string;
}

export interface StorageSanctionRef {
  authority: string;
  listId: string;
  date: string;
  url: string;
}

export interface GetStorageFacilityDetailRequest {
  facilityId: string;
}

export interface GetStorageFacilityDetailResponse {
  facility?: StorageFacilityEntry;
  revisions: StorageFacilityRevisionEntry[];
  fetchedAt: string;
  unavailable: boolean;
}

export interface StorageFacilityRevisionEntry {
  date: string;
  fieldChanged: string;
  previousValue: string;
  newValue: string;
  trigger: string;
  sourcesUsed: string[];
  classifierVersion: string;
}

export interface ListFuelShortagesRequest {
  country: string;
  product: string;
  severity: string;
}

export interface ListFuelShortagesResponse {
  shortages: FuelShortageEntry[];
  fetchedAt: string;
  classifierVersion: string;
  upstreamUnavailable: boolean;
}

export interface FuelShortageEntry {
  id: string;
  country: string;
  product: string;
  severity: string;
  firstSeen: string;
  lastConfirmed: string;
  resolvedAt: string;
  impactTypes: string[];
  causeChain: string[];
  shortDescription: string;
  evidence?: FuelShortageEvidence;
}

export interface FuelShortageEvidence {
  evidenceSources: FuelShortageEvidenceSource[];
  firstRegulatorConfirmation: string;
  classifierVersion: string;
  classifierConfidence: number;
  lastEvidenceUpdate: string;
}

export interface FuelShortageEvidenceSource {
  authority: string;
  title: string;
  url: string;
  date: string;
  sourceType: string;
}

export interface GetFuelShortageDetailRequest {
  shortageId: string;
}

export interface GetFuelShortageDetailResponse {
  shortage?: FuelShortageEntry;
  fetchedAt: string;
  unavailable: boolean;
}

export interface ListEnergyDisruptionsRequest {
  assetId: string;
  assetType: string;
  ongoingOnly: boolean;
}

export interface ListEnergyDisruptionsResponse {
  events: EnergyDisruptionEntry[];
  fetchedAt: string;
  classifierVersion: string;
  upstreamUnavailable: boolean;
}

export interface EnergyDisruptionEntry {
  id: string;
  assetId: string;
  assetType: string;
  eventType: string;
  startAt: string;
  endAt: string;
  capacityOfflineBcmYr: number;
  capacityOfflineMbd: number;
  causeChain: string[];
  shortDescription: string;
  sources: EnergyDisruptionSource[];
  classifierVersion: string;
  classifierConfidence: number;
  lastEvidenceUpdate: string;
}

export interface EnergyDisruptionSource {
  authority: string;
  title: string;
  url: string;
  date: string;
  sourceType: string;
}

export type CorridorStatus = "CORRIDOR_STATUS_UNSPECIFIED" | "CORRIDOR_STATUS_ACTIVE" | "CORRIDOR_STATUS_PROPOSED" | "CORRIDOR_STATUS_UNAVAILABLE";

export type DependencyFlag = "DEPENDENCY_FLAG_UNSPECIFIED" | "DEPENDENCY_FLAG_SINGLE_SOURCE_CRITICAL" | "DEPENDENCY_FLAG_SINGLE_CORRIDOR_CRITICAL" | "DEPENDENCY_FLAG_COMPOUND_RISK" | "DEPENDENCY_FLAG_DIVERSIFIABLE";

export type WarRiskTier = "WAR_RISK_TIER_UNSPECIFIED" | "WAR_RISK_TIER_NORMAL" | "WAR_RISK_TIER_ELEVATED" | "WAR_RISK_TIER_HIGH" | "WAR_RISK_TIER_CRITICAL" | "WAR_RISK_TIER_WAR_ZONE";

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

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

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

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

  async getShippingRates(_req: GetShippingRatesRequest, options?: SupplyChainServiceCallOptions): Promise<GetShippingRatesResponse> {
    let path = "/api/supply-chain/v1/get-shipping-rates";
    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 GetShippingRatesResponse;
  }

  async getChokepointStatus(_req: GetChokepointStatusRequest, options?: SupplyChainServiceCallOptions): Promise<GetChokepointStatusResponse> {
    let path = "/api/supply-chain/v1/get-chokepoint-status";
    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 GetChokepointStatusResponse;
  }

  async getChokepointHistory(req: GetChokepointHistoryRequest, options?: SupplyChainServiceCallOptions): Promise<GetChokepointHistoryResponse> {
    let path = "/api/supply-chain/v1/get-chokepoint-history";
    const params = new URLSearchParams();
    if (req.chokepointId != null && req.chokepointId !== "") params.set("chokepointId", String(req.chokepointId));
    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 GetChokepointHistoryResponse;
  }

  async getCriticalMinerals(_req: GetCriticalMineralsRequest, options?: SupplyChainServiceCallOptions): Promise<GetCriticalMineralsResponse> {
    let path = "/api/supply-chain/v1/get-critical-minerals";
    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 GetCriticalMineralsResponse;
  }

  async getShippingStress(_req: GetShippingStressRequest, options?: SupplyChainServiceCallOptions): Promise<GetShippingStressResponse> {
    let path = "/api/supply-chain/v1/get-shipping-stress";
    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 GetShippingStressResponse;
  }

  async getCountryChokepointIndex(req: GetCountryChokepointIndexRequest, options?: SupplyChainServiceCallOptions): Promise<GetCountryChokepointIndexResponse> {
    let path = "/api/supply-chain/v1/get-country-chokepoint-index";
    const params = new URLSearchParams();
    if (req.iso2 != null && req.iso2 !== "") params.set("iso2", String(req.iso2));
    if (req.hs2 != null && req.hs2 !== "") params.set("hs2", String(req.hs2));
    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 GetCountryChokepointIndexResponse;
  }

  async getBypassOptions(req: GetBypassOptionsRequest, options?: SupplyChainServiceCallOptions): Promise<GetBypassOptionsResponse> {
    let path = "/api/supply-chain/v1/get-bypass-options";
    const params = new URLSearchParams();
    if (req.chokepointId != null && req.chokepointId !== "") params.set("chokepointId", String(req.chokepointId));
    if (req.cargoType != null && req.cargoType !== "") params.set("cargoType", String(req.cargoType));
    if (req.closurePct != null && req.closurePct !== 0) params.set("closurePct", String(req.closurePct));
    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 GetBypassOptionsResponse;
  }

  async getCountryCostShock(req: GetCountryCostShockRequest, options?: SupplyChainServiceCallOptions): Promise<GetCountryCostShockResponse> {
    let path = "/api/supply-chain/v1/get-country-cost-shock";
    const params = new URLSearchParams();
    if (req.iso2 != null && req.iso2 !== "") params.set("iso2", String(req.iso2));
    if (req.chokepointId != null && req.chokepointId !== "") params.set("chokepointId", String(req.chokepointId));
    if (req.hs2 != null && req.hs2 !== "") params.set("hs2", String(req.hs2));
    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 GetCountryCostShockResponse;
  }

  async getCountryProducts(req: GetCountryProductsRequest, options?: SupplyChainServiceCallOptions): Promise<GetCountryProductsResponse> {
    let path = "/api/supply-chain/v1/get-country-products";
    const params = new URLSearchParams();
    if (req.iso2 != null && req.iso2 !== "") params.set("iso2", String(req.iso2));
    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 GetCountryProductsResponse;
  }

  async getMultiSectorCostShock(req: GetMultiSectorCostShockRequest, options?: SupplyChainServiceCallOptions): Promise<GetMultiSectorCostShockResponse> {
    let path = "/api/supply-chain/v1/get-multi-sector-cost-shock";
    const params = new URLSearchParams();
    if (req.iso2 != null && req.iso2 !== "") params.set("iso2", String(req.iso2));
    if (req.chokepointId != null && req.chokepointId !== "") params.set("chokepointId", String(req.chokepointId));
    if (req.closureDays != null && req.closureDays !== 0) params.set("closureDays", String(req.closureDays));
    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 GetMultiSectorCostShockResponse;
  }

  async getSectorDependency(req: GetSectorDependencyRequest, options?: SupplyChainServiceCallOptions): Promise<GetSectorDependencyResponse> {
    let path = "/api/supply-chain/v1/get-sector-dependency";
    const params = new URLSearchParams();
    if (req.iso2 != null && req.iso2 !== "") params.set("iso2", String(req.iso2));
    if (req.hs2 != null && req.hs2 !== "") params.set("hs2", String(req.hs2));
    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 GetSectorDependencyResponse;
  }

  async getRouteExplorerLane(req: GetRouteExplorerLaneRequest, options?: SupplyChainServiceCallOptions): Promise<GetRouteExplorerLaneResponse> {
    let path = "/api/supply-chain/v1/get-route-explorer-lane";
    const params = new URLSearchParams();
    if (req.fromIso2 != null && req.fromIso2 !== "") params.set("fromIso2", String(req.fromIso2));
    if (req.toIso2 != null && req.toIso2 !== "") params.set("toIso2", String(req.toIso2));
    if (req.hs2 != null && req.hs2 !== "") params.set("hs2", String(req.hs2));
    if (req.cargoType != null && req.cargoType !== "") params.set("cargoType", String(req.cargoType));
    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 GetRouteExplorerLaneResponse;
  }

  async getRouteImpact(req: GetRouteImpactRequest, options?: SupplyChainServiceCallOptions): Promise<GetRouteImpactResponse> {
    let path = "/api/supply-chain/v1/get-route-impact";
    const params = new URLSearchParams();
    if (req.fromIso2 != null && req.fromIso2 !== "") params.set("fromIso2", String(req.fromIso2));
    if (req.toIso2 != null && req.toIso2 !== "") params.set("toIso2", String(req.toIso2));
    if (req.hs2 != null && req.hs2 !== "") params.set("hs2", String(req.hs2));
    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 GetRouteImpactResponse;
  }

  async listPipelines(req: ListPipelinesRequest, options?: SupplyChainServiceCallOptions): Promise<ListPipelinesResponse> {
    let path = "/api/supply-chain/v1/list-pipelines";
    const params = new URLSearchParams();
    if (req.commodityType != null && req.commodityType !== "") params.set("commodityType", String(req.commodityType));
    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 ListPipelinesResponse;
  }

  async getPipelineDetail(req: GetPipelineDetailRequest, options?: SupplyChainServiceCallOptions): Promise<GetPipelineDetailResponse> {
    let path = "/api/supply-chain/v1/get-pipeline-detail";
    const params = new URLSearchParams();
    if (req.pipelineId != null && req.pipelineId !== "") params.set("pipelineId", String(req.pipelineId));
    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 GetPipelineDetailResponse;
  }

  async listStorageFacilities(req: ListStorageFacilitiesRequest, options?: SupplyChainServiceCallOptions): Promise<ListStorageFacilitiesResponse> {
    let path = "/api/supply-chain/v1/list-storage-facilities";
    const params = new URLSearchParams();
    if (req.facilityType != null && req.facilityType !== "") params.set("facilityType", String(req.facilityType));
    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 ListStorageFacilitiesResponse;
  }

  async getStorageFacilityDetail(req: GetStorageFacilityDetailRequest, options?: SupplyChainServiceCallOptions): Promise<GetStorageFacilityDetailResponse> {
    let path = "/api/supply-chain/v1/get-storage-facility-detail";
    const params = new URLSearchParams();
    if (req.facilityId != null && req.facilityId !== "") params.set("facilityId", String(req.facilityId));
    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 GetStorageFacilityDetailResponse;
  }

  async listFuelShortages(req: ListFuelShortagesRequest, options?: SupplyChainServiceCallOptions): Promise<ListFuelShortagesResponse> {
    let path = "/api/supply-chain/v1/list-fuel-shortages";
    const params = new URLSearchParams();
    if (req.country != null && req.country !== "") params.set("country", String(req.country));
    if (req.product != null && req.product !== "") params.set("product", String(req.product));
    if (req.severity != null && req.severity !== "") params.set("severity", String(req.severity));
    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 ListFuelShortagesResponse;
  }

  async getFuelShortageDetail(req: GetFuelShortageDetailRequest, options?: SupplyChainServiceCallOptions): Promise<GetFuelShortageDetailResponse> {
    let path = "/api/supply-chain/v1/get-fuel-shortage-detail";
    const params = new URLSearchParams();
    if (req.shortageId != null && req.shortageId !== "") params.set("shortageId", String(req.shortageId));
    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 GetFuelShortageDetailResponse;
  }

  async listEnergyDisruptions(req: ListEnergyDisruptionsRequest, options?: SupplyChainServiceCallOptions): Promise<ListEnergyDisruptionsResponse> {
    let path = "/api/supply-chain/v1/list-energy-disruptions";
    const params = new URLSearchParams();
    if (req.assetId != null && req.assetId !== "") params.set("assetId", String(req.assetId));
    if (req.assetType != null && req.assetType !== "") params.set("assetType", String(req.assetType));
    if (req.ongoingOnly) params.set("ongoingOnly", String(req.ongoingOnly));
    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 ListEnergyDisruptionsResponse;
  }

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

