import type { LegalCaseType, LegalCaseSeverity } from "@prisma/client";
import type {
  LegalDocumentGenerationInput,
  LegalDocumentGenerationOutput,
  LegalTemplateKey,
  LegalTemplateView,
} from "@/lib/legal/types";

const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
const DEFAULT_OPENAI_MODEL = "gpt-4.1-mini";
const DEFAULT_TIMEOUT_MS = 60_000;

const LEGAL_TEMPLATE_CATALOG: Record<LegalTemplateKey, LegalTemplateView> = {
  general_delivery_record: {
    key: "general_delivery_record",
    category: "general",
    title: "Acta entrega-recepcion",
    body: `ACTA DE ENTREGA-RECEPCION\n\nFecha: {{fecha}}\nEmpresa: {{companyName}}\nContraparte: {{counterparty}}\n\nSe deja constancia de la entrega de bienes/servicios conforme al contrato aplicable.\n\nDetalle: {{description}}\n\nFirmas:\n- Representante empresa\n- Representante contraparte`,
  },
  breach_disagreement_letter: {
    key: "breach_disagreement_letter",
    category: "breach",
    title: "Carta de inconformidad por incumplimiento",
    body: `CARTA DE INCONFORMIDAD\n\nA quien corresponda:\n\nPor medio del presente escrito, {{companyName}} manifiesta inconformidad por incumplimiento contractual de {{counterparty}}.\n\nHechos: {{description}}\nObjetivo: {{objective}}\n\nSolicitamos atencion y respuesta dentro del plazo legal aplicable.`,
  },
  payment_release_request: {
    key: "payment_release_request",
    category: "payment",
    title: "Solicitud de liberacion de pago",
    body: `SOLICITUD DE LIBERACION DE PAGO\n\nEmpresa solicitante: {{companyName}}\nContraparte: {{counterparty}}\nMonto en riesgo: {{amountAtRisk}}\n\nSe solicita la liberacion inmediata del pago retenido, derivado de las obligaciones cumplidas conforme al contrato.\n\nSoporte: {{description}}`,
  },
  sanctions_challenge_resource: {
    key: "sanctions_challenge_resource",
    category: "sanctions",
    title: "Recurso de inconformidad por sancion",
    body: `RECURSO DE INCONFORMIDAD\n\nPromovente: {{companyName}}\nAutoridad/Contraparte: {{counterparty}}\n\nSe promueve recurso en contra de la sancion impuesta, por considerarla improcedente.\n\nAntecedentes: {{description}}\nPretension: {{objective}}`,
  },
};

type OpenAiChatCompletionResponse = {
  choices?: Array<{
    message?: {
      content?: string | null;
    };
  }>;
  model?: string;
  usage?: {
    prompt_tokens?: number;
    completion_tokens?: number;
    total_tokens?: number;
  };
  error?: {
    message?: string;
  };
};

function parsePositiveInteger(value: string | undefined, fallback: number) {
  const parsed = Number.parseInt((value ?? "").trim(), 10);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}

function getOpenAiApiKey() {
  return process.env.OPENAI_API_KEY?.trim() || process.env.API_KEY?.trim() || process.env.api_key?.trim() || "";
}

function toCaseLabel(caseType: LegalCaseType) {
  if (caseType === "PAYMENT_RETENTION") {
    return "Retencion de pagos";
  }

  if (caseType === "UNJUST_SANCTION") {
    return "Sancion injustificada";
  }

  if (caseType === "CONTRACT_DISPUTE") {
    return "Controversia contractual";
  }

  return "Incumplimiento contractual";
}

function toSeverityLabel(severity: LegalCaseSeverity) {
  if (severity === "HIGH") {
    return "Alta";
  }

  if (severity === "MEDIUM") {
    return "Media";
  }

  return "Baja";
}

function compactText(value: string, maxLength = 1_500) {
  const compacted = value.replace(/\s+/g, " ").trim();
  if (!compacted) {
    return "";
  }

  return compacted.length > maxLength ? compacted.slice(0, maxLength) : compacted;
}

function interpolateTemplate(template: string, input: LegalDocumentGenerationInput) {
  const date = new Date().toLocaleDateString("es-MX", {
    year: "numeric",
    month: "long",
    day: "2-digit",
  });

  return template
    .replaceAll("{{fecha}}", date)
    .replaceAll("{{companyName}}", input.companyName)
    .replaceAll("{{counterparty}}", input.counterparty)
    .replaceAll("{{amountAtRisk}}", input.amountAtRisk ? `$${input.amountAtRisk.toLocaleString("es-MX")}` : "No especificado")
    .replaceAll("{{description}}", input.description)
    .replaceAll("{{objective}}", input.objective);
}

function buildTemplateFallback(input: LegalDocumentGenerationInput): LegalDocumentGenerationOutput {
  const defaultTemplateKey: LegalTemplateKey =
    input.caseType === "PAYMENT_RETENTION"
      ? "payment_release_request"
      : input.caseType === "UNJUST_SANCTION"
        ? "sanctions_challenge_resource"
        : "breach_disagreement_letter";

  const selectedTemplate = LEGAL_TEMPLATE_CATALOG[input.templateKey ?? defaultTemplateKey];
  const content = interpolateTemplate(selectedTemplate.body, input);

  return {
    title: selectedTemplate.title,
    content,
    engine: "template_fallback",
    model: null,
    warnings: ["Generado con plantilla base. Requiere validacion legal antes de presentar."],
    usage: null,
  };
}

function extractJson(raw: string) {
  const trimmed = raw.trim();

  try {
    return JSON.parse(trimmed) as unknown;
  } catch {
    // Continue with safe extraction.
  }

  const noFence = trimmed
    .replace(/^```json\s*/i, "")
    .replace(/^```\s*/i, "")
    .replace(/\s*```$/i, "")
    .trim();

  const first = noFence.indexOf("{");
  const last = noFence.lastIndexOf("}");

  if (first >= 0 && last > first) {
    return JSON.parse(noFence.slice(first, last + 1)) as unknown;
  }

  throw new Error("Respuesta de IA sin JSON valido.");
}

async function callOpenAi(input: LegalDocumentGenerationInput): Promise<LegalDocumentGenerationOutput> {
  const apiKey = getOpenAiApiKey();

  if (!apiKey) {
    throw new Error("No se encontro API key para OpenAI.");
  }

  const model = process.env.OPENAI_LEGAL_MODEL?.trim() || DEFAULT_OPENAI_MODEL;
  const timeoutMs = parsePositiveInteger(process.env.OPENAI_LEGAL_TIMEOUT_MS, DEFAULT_TIMEOUT_MS);
  const baseUrl = (process.env.OPENAI_API_BASE_URL?.trim() || DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, "");

  const systemPrompt = [
    "Eres abogado de contratacion publica en Mexico.",
    "Redacta borradores legales estructurados y claros.",
    "Responde solo JSON con claves title y content.",
    "Incorpora advertencia de validacion legal cuando aplique.",
  ].join(" ");

  const userPrompt = [
    `Tipo de caso: ${toCaseLabel(input.caseType)}`,
    `Severidad: ${toSeverityLabel(input.severity)}`,
    `Empresa: ${input.companyName}`,
    `Contraparte: ${input.counterparty}`,
    `Monto en riesgo: ${input.amountAtRisk ?? "No especificado"}`,
    `Objetivo legal: ${input.objective}`,
    "Descripcion del caso:",
    compactText(input.description, 2_000),
    "Genera un escrito legal breve con: encabezado, hechos, fundamentos, peticion y cierre.",
  ].join("\n\n");

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(`${baseUrl}/chat/completions`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model,
        temperature: 0.2,
        response_format: {
          type: "json_object",
        },
        messages: [
          { role: "system", content: systemPrompt },
          { role: "user", content: userPrompt },
        ],
      }),
      signal: controller.signal,
    });

    const payload = (await response.json().catch(() => ({}))) as OpenAiChatCompletionResponse;

    if (!response.ok) {
      throw new Error(payload.error?.message ?? `OpenAI error ${response.status}`);
    }

    const content = payload.choices?.[0]?.message?.content;

    if (!content) {
      throw new Error("OpenAI no devolvio contenido util.");
    }

    const parsed = extractJson(content) as { title?: unknown; content?: unknown };
    const title = typeof parsed.title === "string" ? compactText(parsed.title, 220) : "Escrito legal";
    const body = typeof parsed.content === "string" ? parsed.content.trim() : "";

    if (!body) {
      throw new Error("OpenAI devolvio un contenido vacio.");
    }

    return {
      title,
      content: body,
      engine: "openai_json_object",
      model: payload.model ?? model,
      warnings: ["Borrador generado por IA. Requiere validacion legal."],
      usage: {
        promptTokens: payload.usage?.prompt_tokens ?? null,
        completionTokens: payload.usage?.completion_tokens ?? null,
        totalTokens: payload.usage?.total_tokens ?? null,
      },
    };
  } finally {
    clearTimeout(timer);
  }
}

export function listLegalTemplates() {
  return Object.values(LEGAL_TEMPLATE_CATALOG);
}

export async function generateLegalDocument(input: LegalDocumentGenerationInput): Promise<LegalDocumentGenerationOutput> {
  try {
    return await callOpenAi(input);
  } catch (error) {
    const fallback = buildTemplateFallback(input);
    fallback.warnings.push(error instanceof Error ? error.message : "No fue posible generar escrito con IA.");
    return fallback;
  }
}
