/**
 * Enrichment pass: fetch full details from SEAP API for announcements
 * that only have summary data (from data.gov.ro import).
 *
 * Adds: submission deadline, documents, description, lots, award criteria,
 * number of offers, guarantee, subcontracting %.
 *
 * Tries both old (e-licitatie.ro) and new (anunturi.e-licitatie.ro) domains.
 */

import { config } from './config.js';
import { query, pool } from './db.js';
import { sleep } from './seap-client.js';

// Try multiple base URLs — SEAP is in migration
const BASE_URLS = [
  'https://e-licitatie.ro/api-pub',
  'https://anunturi.e-licitatie.ro/api-pub',
];

const REFERERS = [
  'https://e-licitatie.ro/',
  'https://anunturi.e-licitatie.ro/',
];

async function seapFetch(endpoint: string): Promise<any> {
  for (let i = 0; i < BASE_URLS.length; i++) {
    try {
      const res = await fetch(`${BASE_URLS[i]}/${endpoint}`, {
        headers: {
          'Content-Type': 'application/json',
          'Referer': REFERERS[i],
        },
        // @ts-ignore — Node 22 supports this
        signal: AbortSignal.timeout(15000),
      });

      if (res.ok) {
        return await res.json();
      }
    } catch {
      continue;
    }
  }
  return null;
}

// Map ref_number prefix to SEAP notice detail endpoint
function getDetailEndpoint(type: string, refNumber: string): string | null {
  const numericId = refNumber.replace(/\D/g, '');
  if (!numericId) return null;

  switch (type) {
    case 'initiere':
    case 'contract':
    case 'atribuire_fara':
    case 'modificare':
      return `C_PUBLIC_CANotice/get/${numericId}`;
    case 'da':
      return `PublicDirectAcquisition/getView/${numericId}`;
    case 'notificare':
      return `PublicDirectAcquisition/getView/${numericId}`;
    default:
      return null;
  }
}

function extractDetails(type: string, detail: any): Record<string, any> {
  if (!detail) return {};

  // For notices (initiere, contract, atribuire_fara, modificare)
  if (['initiere', 'contract', 'atribuire_fara', 'modificare'].includes(type)) {
    const edit = detail?.caNoticeEdit_New;
    const s1 = edit?.section1_New?.section1_1;
    const s2 = edit?.section2_New?.section2_1_New;
    const s3 = edit?.section3;
    const s4 = edit?.section4_New;

    // Documents
    const docs = detail?.documents || detail?.noticeDocuments || [];

    // Lots
    const lotList = edit?.section2_New?.section2_2_New?.descriptionList || [];
    const lots = lotList.map((lot: any) => ({
      number: lot.lotNumber,
      title: lot.lotTitle,
      description: lot.shortDescription,
      cpvCode: lot.mainCPVCode?.localeKey,
      estimatedValue: lot.estimatedValue,
    }));

    // Submission deadline
    const deadline = s4?.section4_1_New?.tenderReceiptDeadline
      || s4?.tenderReceiptDeadline;

    // Award criteria
    const criteria = s4?.section4_1_New?.awardCriteriaList || [];

    return {
      description: s2?.shortDescription || s2?.contractTitle,
      submission_deadline: deadline || null,
      documents: docs.length > 0 ? JSON.stringify(docs.map((d: any) => ({
        name: d.name || d.fileName,
        url: d.url || d.downloadUrl,
        size: d.fileSize,
      }))) : null,
      num_offers: detail?.noticeContracts?.items?.[0]?.numberOfOffers || null,
      guarantee_value: s3?.guaranteeValue || null,
      lots: lots.length > 0 ? JSON.stringify(lots) : null,
      award_criteria: criteria.length > 0 ? JSON.stringify(criteria.map((c: any) => ({
        name: c.name,
        weight: c.weight,
      }))) : null,
      details: JSON.stringify(detail),
    };
  }

  // For DA
  if (type === 'da' || type === 'notificare') {
    return {
      description: detail.directAcquisitionDescription || detail.directAcquisitionName,
      documents: detail.documents?.length > 0 ? JSON.stringify(detail.documents) : null,
      details: JSON.stringify(detail),
    };
  }

  return {};
}

export async function enrichAnnouncements(limit = 500): Promise<number> {
  // Get un-enriched announcements, prioritize initiere + contract (most detailed)
  const result = await query(`
    SELECT id, type, ref_number FROM seap.announcements
    WHERE enriched_at IS NULL
      AND type IN ('initiere', 'contract', 'atribuire_fara')
    ORDER BY
      CASE type WHEN 'initiere' THEN 1 WHEN 'contract' THEN 2 ELSE 3 END,
      publication_date DESC NULLS LAST
    LIMIT $1
  `, [limit]);

  console.log(`[Enrich] ${result.rows.length} announcements to enrich`);

  let enriched = 0;
  let failed = 0;

  for (const row of result.rows) {
    const endpoint = getDetailEndpoint(row.type, row.ref_number);
    if (!endpoint) {
      failed++;
      continue;
    }

    await sleep(500); // 2 req/s

    const detail = await seapFetch(endpoint);
    if (!detail) {
      failed++;
      // Mark as attempted so we don't retry endlessly
      await query(
        `UPDATE seap.announcements SET enriched_at = now(), details = '{"error":"fetch_failed"}'::jsonb WHERE id = $1`,
        [row.id]
      );
      continue;
    }

    const extracted = extractDetails(row.type, detail);

    await query(`
      UPDATE seap.announcements SET
        description = COALESCE($2, description),
        submission_deadline = COALESCE($3::timestamptz, submission_deadline),
        documents = COALESCE($4::jsonb, documents),
        num_offers = COALESCE($5, num_offers),
        guarantee_value = COALESCE($6, guarantee_value),
        lots = COALESCE($7::jsonb, lots),
        award_criteria = COALESCE($8::jsonb, award_criteria),
        details = COALESCE($9::jsonb, details),
        enriched_at = now()
      WHERE id = $1
    `, [
      row.id,
      extracted.description || null,
      extracted.submission_deadline || null,
      extracted.documents || null,
      extracted.num_offers || null,
      extracted.guarantee_value || null,
      extracted.lots || null,
      extracted.award_criteria || null,
      extracted.details || null,
    ]);

    enriched++;

    if (enriched % 50 === 0) {
      console.log(`[Enrich] ${enriched} done, ${failed} failed`);
    }
  }

  console.log(`[Enrich] Complete: ${enriched} enriched, ${failed} failed`);
  return enriched;
}
