import "server-only";

import { PDFParse } from "pdf-parse";

export type ActaExtractedData = {
  legalName: string | null;
  rfc: string | null;
  incorporationDate: string | null;
  deedNumber: string | null;
  notaryName: string | null;
  legalRepresentative: string | null;
  fiscalAddress: string | null;
  businessPurpose: string | null;
  stateOfIncorporation: string | null;
  extractedFields: string[];
  confidence: "low" | "medium" | "high";
  textSnippet: string;
};

function cleanValue(value: string | null | undefined) {
  if (!value) {
    return null;
  }

  const compact = value.replace(/\s+/g, " ").trim();

  if (!compact) {
    return null;
  }

  return compact.length > 320 ? compact.slice(0, 320) : compact;
}

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

function extractByPatterns(text: string, patterns: RegExp[]) {
  for (const pattern of patterns) {
    const match = text.match(pattern);

    if (match?.[1]) {
      const value = cleanValue(match[1]);

      if (value) {
        return value;
      }
    }
  }

  return null;
}

function findLineWithLabel(lines: string[], labels: string[]) {
  const normalizedLabels = labels.map((label) => normalizeSearchText(label));

  for (let index = 0; index < lines.length; index += 1) {
    const currentLine = lines[index];
    const normalizedLine = normalizeSearchText(currentLine);

    const hasLabel = normalizedLabels.some((label) => normalizedLine.includes(label));

    if (!hasLabel) {
      continue;
    }

    const inline = currentLine.split(/[:\-]/).slice(1).join("-").trim();
    const inlineValue = cleanValue(inline);

    if (inlineValue) {
      return inlineValue;
    }

    const nextLine = cleanValue(lines[index + 1] ?? "");

    if (nextLine) {
      return nextLine;
    }
  }

  return null;
}

export async function extractActaDataFromPdf(pdfBuffer: Buffer): Promise<ActaExtractedData> {
  const parser = new PDFParse({ data: pdfBuffer });
  const parsed = await parser.getText();
  await parser.destroy();

  const rawText = parsed.text?.replace(/\u0000/g, " ").trim() ?? "";

  if (!rawText) {
    throw new Error("No fue posible leer texto del PDF.");
  }

  const compactText = rawText.replace(/\s+/g, " ");
  const lines = rawText
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);

  const legalName = extractByPatterns(compactText, [
    /(?:DENOMINACION|RAZON)\s+SOCIAL(?:\s+DE\s+LA\s+SOCIEDAD)?\s*[:\-]?\s*([A-Z0-9&.,'"\-() ]{5,140})/i,
    /SOCIEDAD\s+DENOMINADA\s*[:\-]?\s*([A-Z0-9&.,'"\-() ]{5,140})/i,
  ]);

  const rfcMatch = compactText.match(/\b[A-Z&Ñ]{3,4}\d{6}[A-Z0-9]{3}\b/i);
  const rfc = cleanValue(rfcMatch?.[0] ?? null);

  const incorporationDate = extractByPatterns(compactText, [
    /(?:FECHA\s+DE\s+CONSTITUCION|SE\s+CONSTITUYO\s+EL|CONSTITUIDA\s+EL)\s*[:\-]?\s*([A-Z0-9,./\-\s]{8,80})/i,
    /A\s+LOS\s+([A-Z0-9\s,./-]{10,80})\s+SE\s+CONSTITUYE/i,
  ]);

  const deedNumber = extractByPatterns(compactText, [
    /(?:ESCRITURA(?:\s+PUBLICA)?(?:\s+NUMERO|\s+NO\.?|\s+NÚMERO)?)\s*[:#\-]?\s*([A-Z0-9\-\/]{2,40})/i,
  ]);

  const notaryName = findLineWithLabel(lines, ["NOTARIO PUBLICO", "NOTARIO", "CORREDOR PUBLICO"]);
  const legalRepresentative = findLineWithLabel(lines, ["REPRESENTANTE LEGAL", "APODERADO LEGAL"]);
  const fiscalAddress = findLineWithLabel(lines, ["DOMICILIO FISCAL", "DOMICILIO SOCIAL", "DOMICILIO"]);
  const businessPurpose = findLineWithLabel(lines, ["OBJETO SOCIAL", "OBJETO"]);
  const stateOfIncorporation = findLineWithLabel(lines, ["ESTADO", "ENTIDAD FEDERATIVA"]);

  const extractedFields = Object.entries({
    legalName,
    rfc,
    incorporationDate,
    deedNumber,
    notaryName,
    legalRepresentative,
    fiscalAddress,
    businessPurpose,
    stateOfIncorporation,
  })
    .filter(([, value]) => Boolean(value))
    .map(([field]) => field);

  const confidence: ActaExtractedData["confidence"] =
    extractedFields.length >= 6 ? "high" : extractedFields.length >= 3 ? "medium" : "low";

  return {
    legalName,
    rfc,
    incorporationDate,
    deedNumber,
    notaryName,
    legalRepresentative,
    fiscalAddress,
    businessPurpose,
    stateOfIncorporation,
    extractedFields,
    confidence,
    textSnippet: rawText.slice(0, 1600),
  };
}
