/**
 * DOCX Exporter
 * ──────────────
 * Generates a branded Word document from a ReportDocument.
 * Uses the `docx` library for server-side or client-side generation.
 */

import {
  Document, Packer, Paragraph, TextRun, HeadingLevel, Table, TableRow, TableCell,
  WidthType, AlignmentType, BorderStyle, ShadingType,
  Header, Footer, PageNumber, NumberFormat,
  ImageRun,
} from "docx";
import type { ReportDocument, ReportBlock, ReportMeta } from "./report-export";

// ─── Brand colors ───────────────────────────────────────────────────────────

const BRAND_BLUE = "4F46E5";
const SLATE_700 = "334155";
const SLATE_400 = "94A3B8";
const RED_600 = "DC2626";
const AMBER_600 = "D97706";
const GREEN_600 = "16A34A";
const BLUE_600 = "2563EB";

const SEVERITY_COLORS: Record<string, string> = {
  critical: RED_600, high: "EA580C", medium: AMBER_600, low: BLUE_600,
};

// ─── Generate DOCX ──────────────────────────────────────────────────────────

export async function generateDocx(doc: ReportDocument): Promise<Buffer> {
  const sections = buildDocxSections(doc);

  const document = new Document({
    styles: {
      default: {
        document: {
          run: { font: "Calibri", size: 22, color: SLATE_700 },
          paragraph: { spacing: { after: 120 } },
        },
        heading1: {
          run: { font: "Calibri", size: 36, bold: true, color: BRAND_BLUE },
          paragraph: { spacing: { before: 360, after: 200 } },
        },
        heading2: {
          run: { font: "Calibri", size: 28, bold: true, color: SLATE_700 },
          paragraph: { spacing: { before: 280, after: 160 }, border: { bottom: { color: "E2E8F0", size: 1, style: BorderStyle.SINGLE, space: 4 } } },
        },
        heading3: {
          run: { font: "Calibri", size: 24, bold: true, color: SLATE_700 },
          paragraph: { spacing: { before: 200, after: 120 } },
        },
      },
    },
    sections: [{
      properties: {
        page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } },
      },
      headers: { default: buildHeader(doc.meta) },
      footers: { default: buildFooter(doc.meta) },
      children: sections,
    }],
  });

  return Buffer.from(await Packer.toBuffer(document));
}

// ─── Build sections from ReportBlocks ───────────────────────────────────────

function buildDocxSections(doc: ReportDocument): Paragraph[] {
  const elements: Paragraph[] = [];

  for (const block of doc.blocks) {
    switch (block.type) {
      case "heading":
        elements.push(new Paragraph({
          heading: block.level === 1 ? HeadingLevel.HEADING_1 : block.level === 2 ? HeadingLevel.HEADING_2 : HeadingLevel.HEADING_3,
          children: [new TextRun({ text: block.text })],
        }));
        break;

      case "paragraph":
        elements.push(new Paragraph({
          children: [new TextRun({ text: block.text, size: 22 })],
          spacing: { after: 160 },
        }));
        break;

      case "callout":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.severity.toUpperCase()}: `, bold: true, color: block.severity === "critical" ? RED_600 : block.severity === "warning" ? AMBER_600 : BLUE_600, size: 20 }),
            new TextRun({ text: block.title, bold: true, size: 20 }),
          ],
          shading: { type: ShadingType.CLEAR, fill: block.severity === "critical" ? "FEF2F2" : block.severity === "warning" ? "FFFBEB" : "EFF6FF" },
          spacing: { after: 80 },
          indent: { left: 200 },
        }));
        elements.push(new Paragraph({
          children: [new TextRun({ text: block.body, size: 20, color: SLATE_400 })],
          indent: { left: 200 },
          spacing: { after: 200 },
        }));
        break;

      case "metric_row":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.label}: `, bold: true, size: 22 }),
            new TextRun({ text: block.value, bold: true, size: 24, color: BRAND_BLUE }),
            block.change ? new TextRun({ text: `  (${block.change})`, size: 18, color: block.changeDirection === "up" ? GREEN_600 : block.changeDirection === "down" ? RED_600 : SLATE_400 }) : new TextRun({ text: "" }),
            new TextRun({ text: `  — ${block.source}`, size: 16, color: SLATE_400 }),
          ],
          spacing: { after: 80 },
          bullet: { level: 0 },
        }));
        break;

      case "finding":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.index}. `, bold: true }),
            new TextRun({ text: `[${block.severity.toUpperCase()}] `, bold: true, color: SEVERITY_COLORS[block.severity] ?? SLATE_400, size: 20 }),
            new TextRun({ text: block.title, bold: true }),
          ],
          spacing: { before: 120, after: 60 },
        }));
        elements.push(new Paragraph({
          children: [new TextRun({ text: block.description, size: 20 })],
          indent: { left: 400 },
          spacing: { after: 60 },
        }));
        if (block.evidence) {
          elements.push(new Paragraph({
            children: [new TextRun({ text: `Evidence: ${block.evidence}`, italics: true, size: 18, color: SLATE_400 })],
            indent: { left: 400 },
            spacing: { after: 60 },
          }));
        }
        if (block.impact) {
          elements.push(new Paragraph({
            children: [new TextRun({ text: `Impact: ${block.impact}`, italics: true, size: 18, color: AMBER_600 })],
            indent: { left: 400 },
            spacing: { after: 120 },
          }));
        }
        break;

      case "prediction":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.metric}: `, bold: true }),
            new TextRun({ text: `${block.predicted.toLocaleString()} projected`, bold: true, color: BRAND_BLUE }),
            new TextRun({ text: ` (current: ${block.current.toLocaleString()}) — ${block.confidence} confidence`, size: 20, color: SLATE_400 }),
          ],
          bullet: { level: 0 },
          spacing: { after: 60 },
        }));
        elements.push(new Paragraph({
          children: [new TextRun({ text: `${block.timeframe} · ${block.basis}`, size: 18, color: SLATE_400 })],
          indent: { left: 400 },
          spacing: { after: block.caveat ? 60 : 120 },
        }));
        if (block.caveat) {
          elements.push(new Paragraph({
            children: [new TextRun({ text: block.caveat, italics: true, size: 18, color: AMBER_600 })],
            indent: { left: 400 },
            spacing: { after: 120 },
          }));
        }
        break;

      case "recommendation":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.index}. `, bold: true }),
            new TextRun({ text: `[${block.priority.toUpperCase()}] `, bold: true, color: SEVERITY_COLORS[block.priority] ?? SLATE_400, size: 20 }),
            new TextRun({ text: block.title, bold: true }),
          ],
          spacing: { before: 80, after: 60 },
        }));
        elements.push(new Paragraph({
          children: [new TextRun({ text: block.description, size: 20 })],
          indent: { left: 400 },
          spacing: { after: block.expectedImpact ? 60 : 120 },
        }));
        if (block.expectedImpact) {
          elements.push(new Paragraph({
            children: [new TextRun({ text: `Expected: ${block.expectedImpact}`, size: 18, color: GREEN_600 })],
            indent: { left: 400 },
            spacing: { after: 120 },
          }));
        }
        break;

      case "source_row":
        elements.push(new Paragraph({
          children: [
            new TextRun({ text: `${block.label}: `, size: 20 }),
            new TextRun({ text: block.status, size: 20, color: block.status === "available" ? GREEN_600 : SLATE_400 }),
            block.recordCount ? new TextRun({ text: ` (${block.recordCount} records)`, size: 18, color: SLATE_400 }) : new TextRun({ text: "" }),
          ],
          bullet: { level: 0 },
          spacing: { after: 40 },
        }));
        break;

      case "citation_list":
        for (const item of block.items) {
          elements.push(new Paragraph({
            children: [
              new TextRun({ text: `${item.label} `, bold: true, size: 18, color: BRAND_BLUE }),
              new TextRun({ text: item.title, size: 18 }),
              new TextRun({ text: ` — ${item.sourceName}`, size: 18, color: SLATE_400 }),
              item.url ? new TextRun({ text: `  ${item.url}`, size: 16, color: BLUE_600 }) : new TextRun({ text: "" }),
            ],
            bullet: { level: 0 },
            spacing: { after: 40 },
          }));
        }
        break;

      case "divider":
        elements.push(new Paragraph({
          children: [],
          border: { bottom: { color: "E2E8F0", size: 1, style: BorderStyle.SINGLE, space: 8 } },
          spacing: { before: 200, after: 200 },
        }));
        break;

      case "spacer":
        elements.push(new Paragraph({ children: [], spacing: { after: 200 } }));
        break;

      case "footer":
        elements.push(new Paragraph({
          children: [new TextRun({ text: block.text, italics: true, size: 16, color: SLATE_400 })],
          alignment: AlignmentType.CENTER,
          spacing: { before: 200 },
        }));
        break;
    }
  }

  return elements;
}

// ─── Header / Footer ────────────────────────────────────────────────────────

function buildHeader(meta: ReportMeta): Header {
  return new Header({
    children: [
      new Paragraph({
        children: [
          new TextRun({ text: `${meta.appBrand} · ${meta.clientName}`, size: 16, color: SLATE_400, font: "Calibri" }),
        ],
        alignment: AlignmentType.RIGHT,
        spacing: { after: 0 },
      }),
    ],
  });
}

function buildFooter(meta: ReportMeta): Footer {
  return new Footer({
    children: [
      new Paragraph({
        children: [
          new TextRun({ text: `${meta.appBrand} Analysis Report · ${meta.reportDate} · `, size: 14, color: SLATE_400 }),
          new TextRun({ text: "Page ", size: 14, color: SLATE_400 }),
          new TextRun({ children: [PageNumber.CURRENT], size: 14, color: SLATE_400 }),
        ],
        alignment: AlignmentType.CENTER,
      }),
    ],
  });
}
