import { config } from './config.js';

const { baseUrl, referer, rateLimit, retry } = config.seap;

let lastRequestTime = 0;

async function throttle() {
  const minInterval = 1000 / rateLimit.requestsPerSecond;
  const now = Date.now();
  const elapsed = now - lastRequestTime;
  if (elapsed < minInterval) {
    await sleep(minInterval - elapsed);
  }
  lastRequestTime = Date.now();
}

export function sleep(ms: number): Promise<void> {
  return new Promise((r) => setTimeout(r, ms));
}

async function seapFetch<T>(
  endpoint: string,
  options: { method?: string; body?: any } = {}
): Promise<T> {
  const { method = 'GET', body } = options;

  for (let attempt = 0; attempt <= retry.maxRetries; attempt++) {
    await throttle();

    try {
      const res = await fetch(`${baseUrl}/${endpoint}`, {
        method,
        headers: {
          'Content-Type': 'application/json',
          Referer: referer,
        },
        body: body ? JSON.stringify(body) : undefined,
      });

      if (res.status === 429 || res.status === 503) {
        const delay = retry.baseDelayMs * Math.pow(2, attempt);
        console.warn(`SEAP ${res.status} on ${endpoint}, retry in ${delay}ms (attempt ${attempt + 1})`);
        await sleep(delay);
        continue;
      }

      if (!res.ok) {
        const text = await res.text();
        throw new Error(`SEAP ${res.status}: ${text.slice(0, 200)}`);
      }

      return (await res.json()) as T;
    } catch (err: any) {
      if (attempt === retry.maxRetries) throw err;
      if (err.message?.includes('SEAP')) throw err; // don't retry HTTP errors except 429/503
      const delay = retry.baseDelayMs * Math.pow(2, attempt);
      console.warn(`Network error on ${endpoint}, retry in ${delay}ms: ${err.message}`);
      await sleep(delay);
    }
  }

  throw new Error(`Exhausted retries for ${endpoint}`);
}

// ── Types ──

export interface SeapListResponse<T> {
  total: number;
  items: T[];
  searchTooLong: boolean;
}

export interface DaListItem {
  directAcquisitionId: number;
  directAcquisitionName: string;
  sysDirectAcquisitionState: { id: number; text: string };
  uniqueIdentificationCode: string;
  cpvCode: string;
  publicationDate: string;
  finalizationDate: string;
  supplier: string;
  contractingAuthority: string;
  estimatedValueRon: number;
  closingValue: number;
}

export interface DaDetail {
  directAcquisitionID: number;
  directAcquisitionName: string;
  uniqueIdentificationCode: string;
  cpvCode: { id: number; text: string; localeKey: string };
  publicationDate: string;
  finalizationDate: string;
  estimatedValue: number;
  closingValue: number;
  contractingAuthorityID: number;
  supplierId: number;
  sysAcquisitionContractType: { id: number; text: string } | null;
  sysEuropeanFund: { id: number; text: string } | null;
  sysDirectAcquisitionState: { id: number; text: string };
}

export interface NoticeListItem {
  caNoticeId: number;
  noticeNo: string;
  contractTitle: string;
  cpvCode: string;
  cpvCodeAndName: string;
  ronContractValue: number;
  noticeStateDate: string;
  sysProcedureType: { id: number; text: string };
  sysAcquisitionContractType: { id: number; text: string };
  contractingAuthorityNameAndFN: string;
  sysNoticeState: { id: number; text: string };
}

export interface EntityProfile {
  entityId: number;
  entityName: string;
  fiscalNumber: string;
  numericFiscalNumber: string;
  city: string;
  county: string;
  address: string;
  postalCode: string;
  country: string;
  isUtility: boolean;
}

// ── API Methods ──

export async function listDirectAcquisitions(params: {
  pageIndex: number;
  pageSize: number;
  finalizationDateStart: string;
  finalizationDateEnd: string;
}): Promise<SeapListResponse<DaListItem>> {
  return seapFetch<SeapListResponse<DaListItem>>(
    'DirectAcquisitionCommon/GetDirectAcquisitionList/',
    {
      method: 'POST',
      body: {
        pageSize: params.pageSize,
        pageIndex: params.pageIndex,
        showOngoingDa: false,
        sysDirectAcquisitionStateId: 7, // Oferta acceptata
        finalizationDateStart: params.finalizationDateStart,
        finalizationDateEnd: params.finalizationDateEnd,
        sortProperties: [{ sortProperty: 'finalizationDate', descending: true }],
      },
    }
  );
}

export async function getDaDetail(id: number): Promise<DaDetail> {
  return seapFetch<DaDetail>(`PublicDirectAcquisition/getView/${id}`);
}

export async function listNotices(params: {
  pageIndex: number;
  pageSize: number;
  startPublicationDate: string;
  endPublicationDate: string;
}): Promise<SeapListResponse<NoticeListItem>> {
  return seapFetch<SeapListResponse<NoticeListItem>>(
    'NoticeCommon/GetCANoticeList/',
    {
      method: 'POST',
      body: {
        pageSize: params.pageSize,
        pageIndex: params.pageIndex,
        sysNoticeTypeIds: [3, 18], // CAN + SCNA
        sysProcedureStateId: 5,    // Atribuita
        startPublicationDate: params.startPublicationDate,
        endPublicationDate: params.endPublicationDate,
      },
    }
  );
}

export async function getNoticeDetail(id: number): Promise<any> {
  return seapFetch<any>(`C_PUBLIC_CANotice/get/${id}`);
}

export async function getAuthorityProfile(entityId: number): Promise<EntityProfile> {
  return seapFetch<EntityProfile>(`Entity/getCAEntityView/${entityId}`);
}

export async function getSupplierProfile(entityId: number): Promise<EntityProfile> {
  return seapFetch<EntityProfile>(`Entity/getSUEntityView/${entityId}`);
}
