/**
 * Map seap.announcements rows to OCDS 1.1.5 Release Package format.
 * Schema: https://standard.open-contracting.org/1.1/en/schema/release/
 *
 * Coverage notes:
 * - We map: tender (procuringEntity, value, procurementMethod, mainProcurementCategory),
 *   awards[] (suppliers, value, date), contracts[] (period, value, dateSigned), parties[].
 * - We do NOT have yet: bids[], amendments[], milestones[], documents[]. Those fields
 *   are emitted as `null` or omitted to remain spec-valid.
 */

const PUBLISHER = {
  name: 'vreaudigital.ro',
  uri: 'https://vreaudigital.ro',
  scheme: 'RO-PROCUREMENT-AGGREGATOR',
  uid: 'vreaudigital-ro',
};

const OCID_PREFIX = 'ocds-vreaudigital-';
const LICENSE = 'https://creativecommons.org/licenses/by/4.0/';
const PUBLICATION_POLICY = 'https://vreaudigital.ro/api/ocds/policy';

// SEAP procedure codes → OCDS procurement methods
// https://standard.open-contracting.org/1.1/en/schema/codelists/#procurement-method
// Keys are normalized lowercase + ASCII (diacritics stripped) for matching.
const PROCUREMENT_METHOD_MAP: Record<string, { method: string; details?: string }> = {
  'licitatie deschisa': { method: 'open' },
  'licitatie deschisa accelerata': { method: 'open', details: 'accelerated' },
  'licitatie restransa': { method: 'selective' },
  'licitatie restransa accelerata': { method: 'selective', details: 'accelerated' },
  'negociere fara publicare prealabila': { method: 'limited', details: 'negociere-fara-publicare' },
  'negociere cu publicare': { method: 'selective', details: 'negociere-cu-publicare' },
  'procedura competitiva cu negociere': { method: 'selective', details: 'competitiva-cu-negociere' },
  'procedura simplificata': { method: 'open', details: 'procedura-simplificata' },
  'procedura simplificata proprie': { method: 'open', details: 'procedura-simplificata-proprie' },
  'norme proprii (anexa 2b)': { method: 'limited', details: 'norme-proprii-anexa-2b' },
  'cerere de oferta': { method: 'selective', details: 'cerere-de-oferte' },
  'cerere de oferte': { method: 'selective', details: 'cerere-de-oferte' },
  'concurs de solutii': { method: 'open', details: 'concurs-de-solutii' },
  'dialog competitiv': { method: 'selective', details: 'dialog-competitiv' },
  'achizitie directa': { method: 'limited', details: 'achizitie-directa' },
};

function normProcedureKey(s: string): string {
  return s
    .normalize('NFD')
    .replace(/[̀-ͯ]/g, '')
    .toLowerCase()
    .trim();
}

// SEAP type → OCDS release tags
// https://standard.open-contracting.org/1.1/en/schema/codelists/#release-tag
function tagsForType(seapType: string): string[] {
  switch (seapType) {
    case 'initiere':
    case 'pi_notice':
      return ['planning'];
    case 'c_notice':
    case 'rfq_invitation':
      return ['tender'];
    case 'ca_notice':
    case 'rfq_notice':
    case 'ted_notice':
      return ['tender', 'award'];
    case 'da':
    case 'contract':
    case 'atribuire_fara':
      return ['tender', 'award', 'contract'];
    case 'notificare':
      return ['contractAmendment'];
    default:
      return ['tender'];
  }
}

export interface AnnouncementRow {
  id: number;
  ref_number: string | null;
  type: string;
  source: string;
  title: string | null;
  description: string | null;
  publication_date: Date | string | null;
  contract_date: Date | string | null;
  estimated_value: number | string | null;
  awarded_value: number | string | null;
  currency: string | null;
  procedure_type: string | null;
  procedure_state: string | null;
  framework_agreement: boolean | null;
  modification_desc: string | null;
  cpv_code: string | null;
  cpv_name: string | null;
  cpv_division: string | null;
  authority_cui: string | null;
  authority_name: string | null;
  authority_address: string | null;
  authority_email: string | null;
  authority_phone: string | null;
  authority_url: string | null;
  authority_county: string | null;
  authority_siruta: string | null;
  supplier_cui: string | null;
  supplier_name: string | null;
  supplier_address: string | null;
  supplier_county: string | null;
  supplier_siruta: string | null;
  supplier_is_sme: boolean | null;
  contract_has_lots: boolean | null;
  lots_count: number | null;
  seap_url: string | null;
  contract_period_start?: Date | string | null;
  contract_period_end?: Date | string | null;
}

function isoDate(d: Date | string | null | undefined): string | null {
  if (!d) return null;
  const date = typeof d === 'string' ? new Date(d) : d;
  if (isNaN(date.getTime())) return null;
  return date.toISOString();
}

function normCui(cui: string | null | undefined): string | null {
  if (!cui) return null;
  return cui.toUpperCase().replace(/^RO/, '').replace(/\s+/g, '').trim() || null;
}

function partyId(prefix: 'BUYER' | 'SUPPLIER', cui: string | null): string {
  const norm = normCui(cui);
  return norm ? `RO-CUI-${norm}` : `${prefix}-UNKNOWN`;
}

export function ocidFor(announcementId: number): string {
  return `${OCID_PREFIX}${announcementId}`;
}

export function announcementToRelease(row: AnnouncementRow): any {
  const ocid = ocidFor(row.id);
  const releaseDate = isoDate(row.publication_date) || isoDate(row.contract_date) || new Date().toISOString();
  const tags = tagsForType(row.type);

  // Build parties[] — buyer + supplier (if present)
  const parties: any[] = [];

  if (row.authority_cui) {
    const pid = partyId('BUYER', row.authority_cui);
    parties.push({
      id: pid,
      name: row.authority_name,
      identifier: {
        scheme: 'RO-CUI',
        id: normCui(row.authority_cui),
        legalName: row.authority_name,
      },
      roles: ['buyer', 'procuringEntity'],
      address: row.authority_address ? {
        streetAddress: row.authority_address,
        region: row.authority_county || undefined,
        countryName: 'Romania',
      } : undefined,
      contactPoint: (row.authority_email || row.authority_phone || row.authority_url) ? {
        email: row.authority_email || undefined,
        telephone: row.authority_phone || undefined,
        url: row.authority_url || undefined,
      } : undefined,
      details: row.authority_siruta ? { siruta: row.authority_siruta } : undefined,
    });
  }

  if (row.supplier_cui) {
    const pid = partyId('SUPPLIER', row.supplier_cui);
    parties.push({
      id: pid,
      name: row.supplier_name,
      identifier: {
        scheme: 'RO-CUI',
        id: normCui(row.supplier_cui),
        legalName: row.supplier_name,
      },
      roles: ['supplier', 'tenderer'],
      address: (row.supplier_address || row.supplier_county) ? {
        streetAddress: row.supplier_address || undefined,
        region: row.supplier_county || undefined,
        countryName: 'Romania',
      } : undefined,
      details: {
        scale: row.supplier_is_sme === true ? 'sme' : (row.supplier_is_sme === false ? 'large' : undefined),
        siruta: row.supplier_siruta || undefined,
      },
    });
  }

  // Tender block
  const procMap = row.procedure_type
    ? PROCUREMENT_METHOD_MAP[normProcedureKey(row.procedure_type)]
    : undefined;

  const tender: any = {
    id: row.ref_number || `tender-${row.id}`,
    title: row.title || undefined,
    description: row.description || undefined,
    status: row.procedure_state ? row.procedure_state.toLowerCase() : undefined,
    procuringEntity: row.authority_cui ? {
      id: partyId('BUYER', row.authority_cui),
      name: row.authority_name,
    } : undefined,
    procurementMethod: procMap?.method,
    procurementMethodDetails: procMap?.details || row.procedure_type || undefined,
    mainProcurementCategory: cpvToCategory(row.cpv_code),
    value: row.estimated_value != null ? {
      amount: Number(row.estimated_value),
      currency: row.currency || 'RON',
    } : undefined,
    items: row.cpv_code ? [{
      id: '1',
      description: row.cpv_name || row.title || undefined,
      classification: {
        scheme: 'CPV',
        id: row.cpv_code,
        description: row.cpv_name || undefined,
      },
    }] : undefined,
    hasFrameworkAgreement: row.framework_agreement || undefined,
    numberOfLots: row.lots_count || undefined,
  };

  // Awards block — only if we have an awarded value or supplier
  const awards: any[] = [];
  if (row.awarded_value != null || row.supplier_cui) {
    awards.push({
      id: `award-${row.id}`,
      title: row.title || undefined,
      status: row.contract_date ? 'active' : 'pending',
      date: isoDate(row.publication_date) || isoDate(row.contract_date),
      value: row.awarded_value != null ? {
        amount: Number(row.awarded_value),
        currency: row.currency || 'RON',
      } : undefined,
      suppliers: row.supplier_cui ? [{
        id: partyId('SUPPLIER', row.supplier_cui),
        name: row.supplier_name,
      }] : [],
      relatedLots: undefined,
    });
  }

  // Contracts block
  const contracts: any[] = [];
  if (row.contract_date || row.modification_desc) {
    contracts.push({
      id: `contract-${row.id}`,
      awardID: `award-${row.id}`,
      title: row.title || undefined,
      status: 'active',
      dateSigned: isoDate(row.contract_date),
      value: row.awarded_value != null ? {
        amount: Number(row.awarded_value),
        currency: row.currency || 'RON',
      } : undefined,
      period: (row.contract_period_start || row.contract_period_end) ? {
        startDate: isoDate(row.contract_period_start),
        endDate: isoDate(row.contract_period_end),
      } : undefined,
      hasAmendments: !!row.modification_desc,
      amendments: row.modification_desc ? [{
        id: 'amendment-1',
        rationale: row.modification_desc,
      }] : undefined,
    });
  }

  return {
    ocid,
    id: `${row.id}`,
    date: releaseDate,
    tag: tags,
    initiationType: 'tender',
    language: 'ro',
    parties,
    buyer: row.authority_cui ? {
      id: partyId('BUYER', row.authority_cui),
      name: row.authority_name,
    } : undefined,
    tender,
    awards: awards.length > 0 ? awards : undefined,
    contracts: contracts.length > 0 ? contracts : undefined,
    sources: [{
      id: 'seap',
      url: row.seap_url || `https://e-licitatie.ro`,
      title: 'SEAP / e-licitatie.ro',
    }],
  };
}

function cpvToCategory(cpv: string | null): string | undefined {
  if (!cpv || cpv.length < 2) return undefined;
  const div = parseInt(cpv.slice(0, 2));
  if (isNaN(div)) return undefined;
  if (div >= 45 && div <= 45) return 'works';
  if (div >= 14 || (div >= 18 && div <= 44)) return 'goods';
  return 'services';
}

export function buildReleasePackage(rows: AnnouncementRow[], requestUrl: string): any {
  return {
    uri: requestUrl,
    version: '1.1',
    extensions: [],
    publishedDate: new Date().toISOString(),
    publisher: PUBLISHER,
    license: LICENSE,
    publicationPolicy: PUBLICATION_POLICY,
    releases: rows.map(announcementToRelease),
  };
}

export function buildSingleReleasePackage(row: AnnouncementRow, requestUrl: string): any {
  return buildReleasePackage([row], requestUrl);
}
