import { readFile } from "node:fs/promises";
import path from "node:path";
import { PDFArray, PDFDocument, PDFName, PDFString, StandardFonts, rgb, type PDFPage } from "pdf-lib";

type ReportPhoto = { category_code: string; storage_key: string; ai_status: string; ai_quality_score: number | string | null; summary: string | null; findings: unknown; ocr_plate: string | null; plate_match: string | null; ocr_chassis: string | null; chassis_match: string | null; manual_assessment?: string | null; manual_damage_location?: string | null; manual_comments?: string | null; manual_analyst_name?: string | null; manual_updated_at?: string | Date | null; latitude?: number | string | null; longitude?: number | string | null; created_at?: string | Date | null };
type ReportData = { inspection: Record<string, unknown>; review: Record<string, unknown> | null; evaluations: Record<string, unknown>[]; photos: ReportPhoto[] };

const navy = rgb(0.04, 0.15, 0.22), cyan = rgb(0.02, 0.67, 0.82), ink = rgb(0.09, 0.18, 0.24), muted = rgb(0.38, 0.48, 0.53), line = rgb(0.86, 0.9, 0.92), green = rgb(0.02, 0.49, 0.34), amber = rgb(0.65, 0.39, 0.03), red = rgb(0.68, 0.17, 0.2);

function value(input: unknown, fallback = "Não informado") { const text = String(input ?? "").trim(); return text || fallback; }
function decisionLabel(status: unknown) { return ({ approved: "APROVADA", approved_with_notes: "APROVADA COM RESSALVAS", rejected: "REPROVADA", retriage: "RETRIAGEM SOLICITADA", human_review: "ANÁLISE HUMANA NECESSÁRIA" } as Record<string, string>)[String(status)] || "EM ANÁLISE"; }
function drawWrapped(page: PDFPage, text: string, x: number, y: number, maxWidth: number, size: number, font: Awaited<ReturnType<PDFDocument["embedFont"]>>, color = ink, lineHeight = size + 4) {
  const words = text.replace(/\s+/g, " ").split(" "); let line = ""; let cursor = y;
  for (const word of words) { const candidate = line ? `${line} ${word}` : word; if (font.widthOfTextAtSize(candidate, size) > maxWidth && line) { page.drawText(line, { x, y: cursor, size, font, color }); cursor -= lineHeight; line = word; } else line = candidate; }
  if (line) { page.drawText(line, { x, y: cursor, size, font, color }); cursor -= lineHeight; }
  return cursor;
}
function header(page: PDFPage, font: Awaited<ReturnType<PDFDocument["embedFont"]>>, title: string, pageNumber: number) { const { width, height } = page.getSize(); page.drawRectangle({ x: 0, y: height - 72, width, height: 72, color: navy }); page.drawText("GRUPO CAPITAL", { x: 38, y: height - 35, size: 15, font, color: rgb(1, 1, 1) }); page.drawText("AUTOVISTORIA VEICULAR", { x: 38, y: height - 53, size: 10, font, color: rgb(0.55, 0.9, 0.95) }); page.drawText(title, { x: width - 200, y: height - 42, size: 10, font, color: rgb(0.85, 0.95, 0.97) }); page.drawText(`Página ${pageNumber}`, { x: width - 79, y: 22, size: 8, font, color: muted }); page.drawLine({ start: { x: 38, y: 38 }, end: { x: width - 38, y: 38 }, thickness: 0.6, color: line }); }
function findings(value: unknown) { if (Array.isArray(value)) return value.map(String); try { const parsed = JSON.parse(String(value || "[]")); return Array.isArray(parsed) ? parsed.map(String) : []; } catch { return []; } }
async function imageFor(pdf: PDFDocument, storageKey: string) { const root = path.resolve(process.env.STORAGE_PATH || "/app/storage"); const file = path.resolve(root, storageKey); if (!file.startsWith(`${root}${path.sep}`)) return null; const bytes = await readFile(file); const ext = path.extname(file).toLowerCase(); if (ext === ".png") return pdf.embedPng(bytes); if (ext === ".jpg" || ext === ".jpeg") return pdf.embedJpg(bytes); return null; }
function categoryLabel(category: string) { return category.replace(/[_-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase()); }
function locationLabel(photo: ReportPhoto) { return photo.latitude !== null && photo.latitude !== undefined && photo.longitude !== null && photo.longitude !== undefined ? "Localização registrada" : "Localização não registrada"; }
function mapUrl(photo: ReportPhoto) {
  if (photo.latitude === null || photo.latitude === undefined || photo.longitude === null || photo.longitude === undefined) return null;
  const latitude = Number(photo.latitude), longitude = Number(photo.longitude);
  if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return null;
  return `https://www.google.com/maps?q=${encodeURIComponent(`${latitude},${longitude}`)}`;
}
function addExternalLink(pdf: PDFDocument, page: PDFPage, url: string, x: number, y: number, width: number, height: number) {
  const annotation = pdf.context.obj({
    Type: "Annot",
    Subtype: "Link",
    Rect: [x, y, x + width, y + height],
    Border: [0, 0, 0],
    A: { Type: "Action", S: "URI", URI: PDFString.of(url) },
  });
  const annots = page.node.lookupMaybe(PDFName.of("Annots"), PDFArray);
  if (annots) annots.push(annotation);
  else page.node.set(PDFName.of("Annots"), pdf.context.obj([annotation]));
}
function truncate(text: string, length: number) { return text.length > length ? `${text.slice(0, Math.max(0, length - 3)).trim()}...` : text; }
function manualAssessmentLabel(assessment: string | null | undefined) { return ({ no_damage: "Sem avaria ou divergência", damage_light: "Avaria leve", damage_moderate: "Avaria moderada", damage_severe: "Avaria grave", damage_structural: "Avaria estrutural/crítica", plate_divergent: "Placa divergente", chassis_divergent: "Chassi divergente/adulterado" } as Record<string, string>)[String(assessment || "")] || ""; }

export async function buildInspectionReportPdf(data: ReportData) {
  const pdf = await PDFDocument.create(); pdf.setTitle(`Laudo Autovistoria Veicular - ${value(data.inspection.external_id)}`); pdf.setAuthor("Grupo Capital Vistorias"); pdf.setSubject("Laudo de vistoria veicular");
  const regular = await pdf.embedFont(StandardFonts.Helvetica), bold = await pdf.embedFont(StandardFonts.HelveticaBold); const page = pdf.addPage([595.28, 841.89]); header(page, bold, "LAUDO TÉCNICO", 1); const { width, height } = page.getSize();
  page.drawText("Laudo de vistoria veicular", { x: 38, y: height - 112, size: 23, font: bold, color: ink }); page.drawText(`Proposta ${value(data.inspection.external_id)}`, { x: 38, y: height - 132, size: 11, font: regular, color: muted });
  const status = String(data.review?.decision || data.inspection.status);
  const isRegular = status === "approved";
  const isAttention = ["approved_with_notes", "retriage", "human_review", "pending_data"].includes(status);
  const isCritical = ["rejected", "expired", "cancelled"].includes(status);
  const statusColor = isRegular ? green : isCritical ? red : amber;
  const statusBackground = isRegular ? rgb(0.92, 0.98, 0.95) : isAttention ? rgb(1, 0.97, 0.9) : isCritical ? rgb(1, 0.94, 0.95) : rgb(0.95, 0.98, 0.99);
  page.drawRectangle({ x: 38, y: height - 201, width: width - 76, height: 52, color: statusBackground, borderColor: line, borderWidth: 1 });
  page.drawText("DECISÃO", { x: 51, y: height - 169, size: 8, font: bold, color: muted });
  page.drawText(decisionLabel(status), { x: 51, y: height - 190, size: 16, font: bold, color: statusColor });
  page.drawText("ÍNDICE DE RISCO", { x: width - 155, y: height - 169, size: 7.5, font: bold, color: muted });
  page.drawText(`${Number(data.inspection.risk_score || 0)} pts`, { x: width - 155, y: height - 190, size: 16, font: bold, color: ink });
  let y = height - 220; page.drawText("Dados da vistoria", { x: 38, y, size: 14, font: bold, color: ink }); y -= 24;
  const fields = [["Veículo", value(data.inspection.vehicle_description)], ["Placa", value(data.inspection.plate)], ["Chassi", value(data.inspection.chassis)], ["Tipo", value(data.inspection.vehicle_type)], ["Ano/modelo", value(data.inspection.model_year)], ["Responsável", value(data.inspection.responsible_name)], ["Data da solicitação", data.inspection.created_at ? new Date(String(data.inspection.created_at)).toLocaleString("pt-BR") : "Não informado"], ["Versão das regras", value(data.inspection.rules_version, "Padrão Capital")]];
  for (let i = 0; i < fields.length; i += 2) { for (const [offset, field] of [[0, fields[i]], [260, fields[i + 1]]] as const) { if (!field) continue; page.drawText(field[0], { x: 38 + offset, y, size: 8, font: bold, color: muted }); drawWrapped(page, field[1], 38 + offset, y - 13, 220, 10, regular); } y -= 37; }
  y -= 4; page.drawLine({ start: { x: 38, y }, end: { x: width - 38, y }, thickness: 1, color: line }); y -= 23; page.drawText("Conclusão técnica", { x: 38, y, size: 14, font: bold, color: ink }); y -= 19;
  const conclusion = value(data.review?.comments || data.review?.reason || "A decisão exibida foi calculada pelas regras ativas e pelas evidências aceitas. Não há conclusão humana registrada para esta vistoria."); y = drawWrapped(page, conclusion, 38, y, width - 76, 10, regular, ink, 15);
  if (data.evaluations.length) { y -= 7; page.drawText("Regras acionadas", { x: 38, y, size: 12, font: bold, color: ink }); y -= 17; for (const rule of data.evaluations.slice(0, 7)) { page.drawText(`• ${value(rule.rule_name)}${Number(rule.points) ? ` (+${Number(rule.points)} pts)` : ""}`, { x: 44, y, size: 9, font: regular, color: ink }); y -= 14; } }
  let pageNumber = 1;
  const cardWidth = 252.64, columnGap = 14, cardHeight = 305, cardX = [38, 38 + 252.64 + columnGap], cardY = [392, 73], imageInset = 9;
  for (let index = 0; index < data.photos.length; index += 4) {
    const photoPage = pdf.addPage([595.28, 841.89]); pageNumber += 1; header(photoPage, bold, "EVIDÊNCIAS FOTOGRÁFICAS", pageNumber);
    photoPage.drawText("Fotos da vistoria", { x: 38, y: 738, size: 16, font: bold, color: ink });
    const lastIndex = Math.min(data.photos.length, index + 4);
    photoPage.drawText(`Registros ${index + 1} a ${lastIndex} de ${data.photos.length}`, { x: 38, y: 720, size: 9, font: regular, color: muted });
    for (let position = 0; position < 4; position += 1) {
      const photo = data.photos[index + position]; if (!photo) continue;
      const column = position % 2, row = Math.floor(position / 2), x = cardX[column], y = cardY[row], imageX = x + imageInset, imageY = y + 112, maxW = cardWidth - imageInset * 2, maxH = 150;
      photoPage.drawRectangle({ x, y, width: cardWidth, height: cardHeight, color: rgb(0.99, 1, 1), borderColor: line, borderWidth: 1 });
      photoPage.drawText(`${String(index + position + 1).padStart(2, "0")}  ${categoryLabel(value(photo.category_code))}`, { x: x + 11, y: y + 287, size: 9.5, font: bold, color: ink });
      photoPage.drawRectangle({ x: imageX, y: imageY, width: maxW, height: maxH, color: rgb(0.96, 0.98, 0.99), borderColor: line, borderWidth: 0.8 });
      try {
        const image = await imageFor(pdf, photo.storage_key);
        if (image) { const scale = Math.min(maxW / image.width, maxH / image.height); const w = image.width * scale, h = image.height * scale; photoPage.drawImage(image, { x: imageX + (maxW - w) / 2, y: imageY + (maxH - h) / 2, width: w, height: h }); }
        else photoPage.drawText("Formato não suportado", { x: imageX + 48, y: imageY + maxH / 2, size: 8, font: regular, color: amber });
      } catch { photoPage.drawText("Foto indisponível", { x: imageX + 64, y: imageY + maxH / 2, size: 8, font: regular, color: red }); }
      let py = y + 98;
      photoPage.drawText(`Legenda: foto ${categoryLabel(value(photo.category_code)).toLowerCase()}`, { x: x + 11, y: py, size: 7.5, font: bold, color: muted }); py -= 13;
      photoPage.drawText(photo.ai_status === "flagged" ? "Captura aceita com ponto de atenção" : "Captura aceita", { x: x + 11, y: py, size: 7.5, font: regular, color: muted }); py -= 13;
      const locationUrl = mapUrl(photo);
      photoPage.drawText(locationLabel(photo), { x: x + 11, y: py, size: 7.5, font: regular, color: locationUrl ? green : amber }); py -= 11;
      if (locationUrl) {
        const linkText = "Abrir localização no mapa";
        const linkWidth = bold.widthOfTextAtSize(linkText, 7.2);
        photoPage.drawText(linkText, { x: x + 11, y: py, size: 7.2, font: bold, color: cyan });
        photoPage.drawLine({ start: { x: x + 11, y: py - 1.5 }, end: { x: x + 11 + linkWidth, y: py - 1.5 }, thickness: 0.35, color: cyan });
        addExternalLink(pdf, photoPage, locationUrl, x + 9, py - 3, linkWidth + 5, 11);
        py -= 13;
      } else py -= 3;
      const identity = photo.category_code.toLowerCase().includes("placa") ? `Placa: ${photo.plate_match === "matched" ? "confere" : photo.plate_match === "mismatched" ? "divergente" : "não lida"}${photo.ocr_plate ? ` (${photo.ocr_plate})` : ""}` : photo.category_code.toLowerCase().includes("chassi") ? `Chassi: ${photo.chassis_match === "matched" ? "confere" : photo.chassis_match === "mismatched" ? "divergente" : "não lido"}${photo.ocr_chassis ? ` (${photo.ocr_chassis})` : ""}` : "Identificação: não aplicável a esta foto";
      py = drawWrapped(photoPage, identity, x + 11, py, cardWidth - 22, 7.5, bold, photo.plate_match === "mismatched" || photo.chassis_match === "mismatched" ? red : ink, 10); py -= 2;
      const firstFinding = findings(photo.findings)[0]; const aiAnalysis = firstFinding ? `${value(photo.summary, "Sem achado visual registrado.")} Achado: ${firstFinding}` : value(photo.summary, "Sem achado visual registrado.");
      const manualLabel = manualAssessmentLabel(photo.manual_assessment);
      if (manualLabel) {
        photoPage.drawText("Avaliação humana", { x: x + 11, y: py, size: 7.5, font: bold, color: ink }); py -= 10;
        py = drawWrapped(photoPage, manualLabel, x + 11, py, cardWidth - 22, 7.3, bold, ink, 9.5); py -= 1;
        if (photo.manual_damage_location) { py = drawWrapped(photoPage, `Local: ${photo.manual_damage_location}`, x + 11, py, cardWidth - 22, 7.3, regular, ink, 9.5); py -= 1; }
        if (photo.manual_comments) drawWrapped(photoPage, truncate(`Comentário: ${photo.manual_comments}`, 145), x + 11, py, cardWidth - 22, 7.3, regular, ink, 9.5);
      } else {
        photoPage.drawText("Análise do veículo", { x: x + 11, y: py, size: 7.5, font: bold, color: ink }); py -= 10;
        drawWrapped(photoPage, truncate(aiAnalysis, 180), x + 11, py, cardWidth - 22, 7.3, regular, ink, 9.5);
      }
    }
  }
  return Buffer.from(await pdf.save());
}
