import { config } from '../config.js';
import { query } from '../db.js';
import { listDirectAcquisitions, getDaDetail, sleep } from '../seap-client.js';
import { generateDateWindows, monthsAgo } from '../utils/date-ranges.js';
import { ensureAuthority, ensureSupplier } from './entities.js';

export async function scrapeDirectAcquisitions(startDate?: Date): Promise<number> {
  const syncState = await query(
    "SELECT last_date FROM seap.sync_state WHERE source = 'da'"
  );

  const from = startDate
    || (syncState.rows[0]?.last_date ? new Date(syncState.rows[0].last_date) : monthsAgo(config.scraper.backfillMonths));
  const to = new Date();

  console.log(`[DA] Scraping from ${from.toISOString()} to ${to.toISOString()}`);

  const windows = generateDateWindows(from, to, config.scraper.daWindowDays);
  let totalInserted = 0;

  for (const window of windows) {
    console.log(`[DA] Window: ${window.start} → ${window.end}`);

    let pageIndex = 0;
    let hasMore = true;

    while (hasMore) {
      const result = await listDirectAcquisitions({
        pageIndex,
        pageSize: config.scraper.pageSize,
        finalizationDateStart: window.start,
        finalizationDateEnd: window.end,
      });

      if (result.searchTooLong) {
        console.warn(`[DA] searchTooLong in window ${window.start}–${window.end}, results may be capped`);
      }

      console.log(`[DA] Page ${pageIndex}: ${result.items.length} items (total: ${result.total})`);

      let batchCount = 0;
      for (const item of result.items) {
        // Skip if already exists
        const exists = await query(
          'SELECT id FROM seap.direct_acquisitions WHERE id = $1',
          [item.directAcquisitionId]
        );
        if (exists.rows.length > 0) continue;

        // Fetch detail for entity IDs
        let detail;
        try {
          detail = await getDaDetail(item.directAcquisitionId);
        } catch (err: any) {
          console.warn(`[DA] Failed detail for ${item.directAcquisitionId}: ${err.message}`);
          continue;
        }

        // Ensure entities exist
        if (detail.contractingAuthorityID) {
          await ensureAuthority(detail.contractingAuthorityID);
        }
        if (detail.supplierId) {
          await ensureSupplier(detail.supplierId);
        }

        // Parse CPV
        const cpvCode = detail.cpvCode?.localeKey || item.cpvCode?.split(' - ')[0] || null;
        const cpvName = detail.cpvCode?.text || item.cpvCode?.split(' - ').slice(1).join(' - ') || null;

        await query(
          `INSERT INTO seap.direct_acquisitions
             (id, unique_code, name, cpv_code, cpv_name, publication_date, finalization_date,
              estimated_value, closing_value, state_id, state_text,
              contract_type_id, contract_type_text, eu_fund_id, eu_fund_text,
              authority_id, supplier_id)
           VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17)
           ON CONFLICT (id) DO NOTHING`,
          [
            item.directAcquisitionId,
            item.uniqueIdentificationCode || detail.uniqueIdentificationCode,
            item.directAcquisitionName || detail.directAcquisitionName,
            cpvCode,
            cpvName,
            item.publicationDate,
            item.finalizationDate,
            detail.estimatedValue ?? item.estimatedValueRon,
            detail.closingValue ?? item.closingValue,
            detail.sysDirectAcquisitionState?.id,
            detail.sysDirectAcquisitionState?.text,
            detail.sysAcquisitionContractType?.id ?? null,
            detail.sysAcquisitionContractType?.text ?? null,
            detail.sysEuropeanFund?.id ?? null,
            detail.sysEuropeanFund?.text ?? null,
            detail.contractingAuthorityID || null,
            detail.supplierId || null,
          ]
        );

        totalInserted++;
        batchCount++;

        // Batch delay
        if (batchCount >= config.seap.rateLimit.batchSize) {
          console.log(`[DA] Batch pause (${config.seap.rateLimit.batchDelayMs}ms)...`);
          await sleep(config.seap.rateLimit.batchDelayMs);
          batchCount = 0;
        }
      }

      hasMore = (pageIndex + 1) * config.scraper.pageSize < result.total && !result.searchTooLong;
      pageIndex++;
    }

    // Update sync state after each window
    await query(
      `UPDATE seap.sync_state SET last_date = $1, status = 'running', updated_at = now() WHERE source = 'da'`,
      [window.end]
    );
  }

  // Final sync state
  await query(
    `UPDATE seap.sync_state SET status = 'completed', updated_at = now() WHERE source = 'da'`
  );

  console.log(`[DA] Done. Inserted ${totalInserted} new acquisitions.`);
  return totalInserted;
}
