export type LicitationDocumentLink = {
  name: string;
  url: string;
  type: string | null;
};

export type LicitationBundleDocumentKind = "BASES_LICITACION" | "CONVOCATORIA" | "ANEXOS" | "OTRO";

export type RankedLicitationBundleDocument = LicitationDocumentLink & {
  bundleKind: LicitationBundleDocumentKind;
  bundleScore: number;
};

export type LicitationDocumentBundleSelection = {
  bases: RankedLicitationBundleDocument[];
  convocatoria: RankedLicitationBundleDocument[];
  anexos: RankedLicitationBundleDocument[];
  extras: RankedLicitationBundleDocument[];
};

function normalizeText(value: unknown) {
  return typeof value === "string" ? value.trim() : "";
}

function normalizeSearchText(value: string) {
  return value
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase();
}

function isHttpUrl(value: string) {
  try {
    const parsed = new URL(value);
    return parsed.protocol === "http:" || parsed.protocol === "https:";
  } catch {
    return false;
  }
}

function toSearchText(document: LicitationDocumentLink) {
  return normalizeSearchText(`${document.name} ${document.type ?? ""} ${document.url}`);
}

export function inferLicitationBundleDocumentKind(document: LicitationDocumentLink): LicitationBundleDocumentKind {
  const text = toSearchText(document);

  if (/\bbase(s)?\b|\bpliego\b|\bterminos\b|\bespecificaciones\b/.test(text)) {
    return "BASES_LICITACION";
  }

  if (/\bconvocatoria\b|\binvitacion\b|\bllamado\b/.test(text)) {
    return "CONVOCATORIA";
  }

  if (/\banexo(s)?\b|\bapendice\b|\bformato(s)?\b/.test(text)) {
    return "ANEXOS";
  }

  return "OTRO";
}

export function parseLicitationDocumentLinks(value: unknown): LicitationDocumentLink[] {
  if (!Array.isArray(value)) {
    return [];
  }

  const seen = new Set<string>();
  const output: LicitationDocumentLink[] = [];

  for (const item of value) {
    if (!item || typeof item !== "object") {
      continue;
    }

    const record = item as Record<string, unknown>;
    const name = normalizeText(record.name) || "Documento";
    const url = normalizeText(record.url);
    const type = normalizeText(record.type) || null;

    if (!url || !isHttpUrl(url)) {
      continue;
    }

    const signature = `${name.toLowerCase()}|${url}`;
    if (seen.has(signature)) {
      continue;
    }

    seen.add(signature);
    output.push({ name, url, type });
  }

  return output;
}

export function isLikelyPdfUrl(value: string | null | undefined) {
  const url = normalizeText(value);
  if (!url) {
    return false;
  }

  return /\.pdf(?:$|[?#])/i.test(url);
}

export function isPdfDocument(document: LicitationDocumentLink) {
  if (isLikelyPdfUrl(document.url)) {
    return true;
  }

  const lowerType = (document.type ?? "").toLowerCase();
  if (lowerType.includes("pdf") || lowerType.includes("application/pdf")) {
    return true;
  }

  const lowerName = document.name.toLowerCase();
  return lowerName.endsWith(".pdf") || lowerName.includes("pdf");
}

function getPrimaryScore(document: LicitationDocumentLink) {
  const text = toSearchText(document);
  let score = 0;

  if (isPdfDocument(document)) {
    score += 400;
  }

  if (/\bbases?\b|\bconvocatoria\b|\blicitaci[oó]n\b|\bpliego\b|\bt[eé]rminos\b/.test(text)) {
    score += 180;
  }

  if (/\banexo\b|\bformato\b|\bdocumento\b/.test(text)) {
    score += 40;
  }

  if (/\bfallo\b|\badjudicaci[oó]n\b|\bresultado\b|\bacta\b|\baclaraci[oó]n\b/.test(text)) {
    score -= 80;
  }

  if (/\.(zip|rar)(?:$|[?#])/i.test(document.url) || /\bzip\b|\brar\b/.test(text)) {
    score -= 120;
  }

  return score;
}

function getBundleKindBoost(document: LicitationDocumentLink, kind: LicitationBundleDocumentKind) {
  const text = toSearchText(document);

  if (kind === "BASES_LICITACION") {
    if (/\bbase(s)?\b|\bpliego\b|\bterminos\b/.test(text)) {
      return 180;
    }
    if (/\bconvocatoria\b/.test(text)) {
      return 35;
    }
    if (/\banexo(s)?\b/.test(text)) {
      return -20;
    }
    return 0;
  }

  if (kind === "CONVOCATORIA") {
    if (/\bconvocatoria\b|\binvitacion\b/.test(text)) {
      return 180;
    }
    if (/\bbase(s)?\b/.test(text)) {
      return -10;
    }
    if (/\banexo(s)?\b/.test(text)) {
      return -20;
    }
    return 0;
  }

  if (kind === "ANEXOS") {
    if (/\banexo(s)?\b|\bapendice\b/.test(text)) {
      return 180;
    }
    if (/\bformato(s)?\b/.test(text)) {
      return 90;
    }
    if (/\bbase(s)?\b/.test(text)) {
      return -15;
    }
    return 0;
  }

  return 0;
}

function computeBundleScore(document: LicitationDocumentLink, kind: LicitationBundleDocumentKind) {
  return getPrimaryScore(document) + getBundleKindBoost(document, kind);
}

function toRankedBundleDocument(document: LicitationDocumentLink, kind: LicitationBundleDocumentKind): RankedLicitationBundleDocument {
  return {
    ...document,
    bundleKind: kind,
    bundleScore: computeBundleScore(document, kind),
  };
}

function dedupeBundleDocuments(documents: RankedLicitationBundleDocument[]) {
  const seen = new Set<string>();
  const deduped: RankedLicitationBundleDocument[] = [];

  for (const document of documents) {
    const signature = `${document.url}|${document.bundleKind}`;
    if (seen.has(signature)) {
      continue;
    }
    seen.add(signature);
    deduped.push(document);
  }

  return deduped;
}

export function rankLicitationDocumentsForBundle(documents: LicitationDocumentLink[], maxPerKind = 1): LicitationDocumentBundleSelection {
  const ranked = documents.map((document) => {
    const inferredKind = inferLicitationBundleDocumentKind(document);
    return toRankedBundleDocument(document, inferredKind);
  });

  const sortByScore = (left: RankedLicitationBundleDocument, right: RankedLicitationBundleDocument) => right.bundleScore - left.bundleScore;
  const limit = Math.max(1, maxPerKind);

  const bases = dedupeBundleDocuments(ranked.filter((item) => item.bundleKind === "BASES_LICITACION").sort(sortByScore)).slice(0, limit);
  const convocatoria = dedupeBundleDocuments(ranked.filter((item) => item.bundleKind === "CONVOCATORIA").sort(sortByScore)).slice(0, limit);
  const anexos = dedupeBundleDocuments(ranked.filter((item) => item.bundleKind === "ANEXOS").sort(sortByScore)).slice(0, limit);
  const extras = dedupeBundleDocuments(
    ranked
      .filter((item) => item.bundleKind !== "BASES_LICITACION" && item.bundleKind !== "CONVOCATORIA" && item.bundleKind !== "ANEXOS")
      .sort(sortByScore),
  );

  return {
    bases,
    convocatoria,
    anexos,
    extras,
  };
}

export function pickPrimaryLicitationDocument(documents: LicitationDocumentLink[]) {
  if (!documents.length) {
    return null;
  }

  return [...documents]
    .sort((left, right) => getPrimaryScore(right) - getPrimaryScore(left))
    .at(0) ?? null;
}

export function pickPrimaryLicitationPdfDocument(documents: LicitationDocumentLink[]) {
  const pdfDocuments = documents.filter((item) => isPdfDocument(item));
  if (!pdfDocuments.length) {
    return null;
  }

  return pickPrimaryLicitationDocument(pdfDocuments);
}
