import { createHash } from "node:crypto";
import { LicitationCategory, LicitationProcedureType } from "@prisma/client";
import type { MunicipalityConnectorInput, NormalizedDocument, NormalizedLicitationInput } from "@/lib/licitations/types";

function normalizeText(value: string | null | undefined) {
  return (value ?? "").trim().replace(/\s+/g, " ");
}

function normalizeSearchText(value: string | null | undefined) {
  return normalizeText(value).toLowerCase();
}

export function mapProcedureType(value: string | null | undefined): LicitationProcedureType {
  const text = normalizeSearchText(value);

  if (text.includes("adjudicacion directa")) {
    return LicitationProcedureType.ADJUDICACION_DIRECTA;
  }

  if (text.includes("invitacion restringida") || text.includes("invitacion a cuando menos")) {
    return LicitationProcedureType.INVITACION_RESTRINGIDA;
  }

  if (text.includes("licitacion publica") || text.includes("licitacion")) {
    return LicitationProcedureType.LICITACION_PUBLICA;
  }

  return LicitationProcedureType.UNKNOWN;
}

export function mapCategory(value: string | null | undefined): LicitationCategory {
  const text = normalizeSearchText(value);

  const hasGoods = text.includes("bien") || text.includes("insumo") || text.includes("material");
  const hasServices = text.includes("servicio") || text.includes("consultoria");
  const hasWorks = text.includes("obra") || text.includes("construccion") || text.includes("infraestructura");

  const matched = [hasGoods, hasServices, hasWorks].filter(Boolean).length;

  if (matched > 1) {
    return LicitationCategory.MIXED;
  }

  if (hasGoods) {
    return LicitationCategory.GOODS;
  }

  if (hasServices) {
    return LicitationCategory.SERVICES;
  }

  if (hasWorks) {
    return LicitationCategory.WORKS;
  }

  return LicitationCategory.UNKNOWN;
}

export function parseDateMaybe(value: string | null | undefined): Date | null {
  const raw = normalizeText(value);

  if (!raw) {
    return null;
  }

  const isoParsed = new Date(raw);

  if (!Number.isNaN(isoParsed.getTime())) {
    return isoParsed;
  }

  const normalized = raw.replace(/\./g, "/").replace(/-/g, "/");
  const match = normalized.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/);

  if (!match) {
    return null;
  }

  const day = Number.parseInt(match[1] ?? "", 10);
  const month = Number.parseInt(match[2] ?? "", 10);
  const yearInput = Number.parseInt(match[3] ?? "", 10);

  if (!Number.isFinite(day) || !Number.isFinite(month) || !Number.isFinite(yearInput)) {
    return null;
  }

  const year = yearInput < 100 ? yearInput + 2000 : yearInput;
  const parsed = new Date(Date.UTC(year, month - 1, day));

  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed;
}

export function parseAmountAndCurrency(value: string | null | undefined): { amount: number | null; currency: string | null } {
  const raw = normalizeText(value);

  if (!raw) {
    return { amount: null, currency: null };
  }

  const currency = raw.includes("USD") || raw.includes("US$") || raw.includes("dolar") ? "USD" : "MXN";
  const cleaned = raw.replace(/[^0-9.,-]/g, "");

  if (!cleaned) {
    return { amount: null, currency: null };
  }

  const normalized = cleaned.includes(",") && cleaned.includes(".") ? cleaned.replace(/,/g, "") : cleaned.replace(/,/g, ".");
  const amount = Number.parseFloat(normalized);

  return {
    amount: Number.isFinite(amount) ? amount : null,
    currency,
  };
}

export function sanitizeDocuments(documents: NormalizedDocument[] | undefined) {
  if (!documents?.length) {
    return [];
  }

  const seen = new Set<string>();
  const result: NormalizedDocument[] = [];

  for (const doc of documents) {
    const name = normalizeText(doc.name);
    const url = normalizeText(doc.url);

    if (!url) {
      continue;
    }

    const key = `${name.toLowerCase()}|${url}`;

    if (seen.has(key)) {
      continue;
    }

    seen.add(key);
    result.push({
      name: name || "Documento",
      url,
      type: normalizeText(doc.type),
    });
  }

  return result;
}

export function buildStableRecordId(municipality: MunicipalityConnectorInput, item: NormalizedLicitationInput) {
  const text = [
    municipality.id,
    item.title,
    item.publishDate?.toISOString().slice(0, 10) ?? "",
    item.amount == null ? "" : String(item.amount),
    item.documents?.map((document) => document.url).sort().join("|") ?? "",
    item.rawSourceUrl ?? "",
  ]
    .map((value) => normalizeText(value))
    .join("||");

  return createHash("sha256").update(text).digest("hex").slice(0, 40);
}

export function pickFirstText(values: Array<string | null | undefined>) {
  for (const value of values) {
    const normalized = normalizeText(value);

    if (normalized) {
      return normalized;
    }
  }

  return "";
}

export function pickPublishDate(values: Array<string | null | undefined>) {
  for (const value of values) {
    const parsed = parseDateMaybe(value);

    if (parsed) {
      return parsed;
    }
  }

  return null;
}
