/**
 * PPTX export for Report Studio.
 *
 * Turns a BrandReport into a concise 7-slide deck suitable for
 * executive presentations. Client-ready, server-generated via
 * pptxgenjs (outputType "nodebuffer" so it can be streamed from
 * a Next.js route handler).
 */

import PptxGenJS from "pptxgenjs";
import type { BrandReport } from "./report-generator";

export interface PptxBrand {
  name: string;
  domain: string;
  logoUrl?: string;
}

const FONT = "Calibri";
const PRIMARY = "4F46E5";   // indigo-600
const DARK = "0F172A";      // slate-900
const MUTED = "64748B";     // slate-500
const LIGHT = "F1F5F9";     // slate-100
const RED = "DC2626";       // red-600
const RED_BG = "FEE2E2";    // red-100
const WHITE = "FFFFFF";

function shortUrl(url: string, max = 50): string {
  try {
    const u = new URL(url);
    const s = u.pathname === "/" ? u.host : `${u.host}${u.pathname}`;
    return s.length > max ? s.slice(0, max - 1) + "…" : s;
  } catch {
    return url.length > max ? url.slice(0, max - 1) + "…" : url;
  }
}

function fmt(n: number): string {
  if (!Number.isFinite(n)) return "—";
  if (Math.abs(n) >= 1000) return `${(n / 1000).toFixed(1)}k`;
  return n.toFixed(0);
}

export async function exportReportToPptx(
  report: BrandReport,
  brand: PptxBrand,
): Promise<Buffer> {
  const pptx = new PptxGenJS();
  pptx.layout = "LAYOUT_WIDE"; // 13.33 x 7.5 in
  pptx.author = "meSEO";
  pptx.company = brand.name;
  pptx.title = `${brand.name} — SEO Performance Report`;

  const titleOpts = { fontFace: FONT, color: DARK, bold: true };
  const bodyOpts = { fontFace: FONT, color: DARK };

  // ── Slide 1: Title ─────────────────────────────────────────────────
  {
    const s = pptx.addSlide();
    s.background = { color: PRIMARY };
    s.addText(brand.name, {
      x: 0.7, y: 2.3, w: 12, h: 1.0,
      fontFace: FONT, fontSize: 44, bold: true, color: WHITE,
    });
    s.addText("SEO Performance Report", {
      x: 0.7, y: 3.4, w: 12, h: 0.7,
      fontFace: FONT, fontSize: 28, color: WHITE,
    });
    s.addText(
      `${report.dateRange.start} — ${report.dateRange.end}  ·  ${brand.domain}`,
      {
        x: 0.7, y: 4.3, w: 12, h: 0.5,
        fontFace: FONT, fontSize: 16, color: WHITE,
      },
    );
  }

  // ── Slide 2: Executive Summary ─────────────────────────────────────
  {
    const s = pptx.addSlide();
    s.addText("Executive Summary", {
      x: 0.5, y: 0.3, w: 12, h: 0.6,
      ...titleOpts, fontSize: 28,
    });

    // Health score card
    const health = report.executiveSummary.healthScore;
    s.addShape(pptx.ShapeType.roundRect, {
      x: 0.5, y: 1.1, w: 2.6, h: 2.0,
      fill: { color: PRIMARY }, line: { color: PRIMARY }, rectRadius: 0.1,
    });
    s.addText("HEALTH SCORE", {
      x: 0.5, y: 1.2, w: 2.6, h: 0.4,
      fontFace: FONT, fontSize: 11, color: WHITE, align: "center", bold: true,
    });
    s.addText(health != null ? `${health}` : "—", {
      x: 0.5, y: 1.55, w: 2.6, h: 1.2,
      fontFace: FONT, fontSize: 56, bold: true, color: WHITE, align: "center",
    });
    s.addText("/ 100", {
      x: 0.5, y: 2.65, w: 2.6, h: 0.3,
      fontFace: FONT, fontSize: 12, color: WHITE, align: "center",
    });

    // KPI cards — take first 4
    const kpis = report.executiveSummary.kpis.slice(0, 4);
    const kpiW = 2.3;
    const kpiGap = 0.15;
    const kpiStartX = 3.4;
    kpis.forEach((kpi, i) => {
      const x = kpiStartX + i * (kpiW + kpiGap);
      s.addShape(pptx.ShapeType.roundRect, {
        x, y: 1.1, w: kpiW, h: 2.0,
        fill: { color: LIGHT }, line: { color: LIGHT }, rectRadius: 0.08,
      });
      s.addText(kpi.label.toUpperCase(), {
        x, y: 1.2, w: kpiW, h: 0.35,
        fontFace: FONT, fontSize: 10, color: MUTED, align: "center", bold: true,
      });
      const valueText = `${fmt(kpi.value)}${kpi.unit ?? ""}`;
      s.addText(valueText, {
        x, y: 1.6, w: kpiW, h: 0.9,
        fontFace: FONT, fontSize: 28, bold: true, color: DARK, align: "center",
      });
      if (kpi.changePct != null) {
        const up = kpi.direction === "up";
        const arrow = up ? "▲" : kpi.direction === "down" ? "▼" : "■";
        s.addText(`${arrow} ${kpi.changePct.toFixed(1)}%`, {
          x, y: 2.55, w: kpiW, h: 0.4,
          fontFace: FONT, fontSize: 12, bold: true,
          color: up ? "16A34A" : kpi.direction === "down" ? RED : MUTED,
          align: "center",
        });
      }
    });

    // Insights bullets
    const bullets = [
      { label: "Biggest Win", text: report.executiveSummary.topWin ?? "No standout win this period.", color: "16A34A" },
      { label: "Top Concern", text: report.executiveSummary.topConcern ?? "No critical concerns flagged.", color: RED },
      { label: "Opportunity", text: report.executiveSummary.topOpportunity ?? "No opportunities surfaced.", color: PRIMARY },
    ];
    bullets.forEach((b, i) => {
      const y = 3.4 + i * 1.15;
      s.addShape(pptx.ShapeType.rect, {
        x: 0.5, y: y + 0.1, w: 0.1, h: 0.8,
        fill: { color: b.color }, line: { color: b.color },
      });
      s.addText(b.label.toUpperCase(), {
        x: 0.75, y, w: 12, h: 0.35,
        fontFace: FONT, fontSize: 11, bold: true, color: b.color,
      });
      s.addText(b.text, {
        x: 0.75, y: y + 0.35, w: 12, h: 0.7,
        fontFace: FONT, fontSize: 14, color: DARK,
      });
    });
  }

  // ── Slide 3: Top 5 pages by clicks (bar chart) ─────────────────────
  {
    const s = pptx.addSlide();
    s.addText("Top 5 Pages by Clicks", {
      x: 0.5, y: 0.3, w: 12, h: 0.6,
      ...titleOpts, fontSize: 28,
    });

    const top5 = report.wins.topPages.slice(0, 5);
    if (top5.length > 0) {
      const labels = top5.map((p) => shortUrl(p.url, 40));
      const values = top5.map((p) => p.clicks);
      s.addChart(pptx.ChartType.bar, [{
        name: "Clicks",
        labels,
        values,
      }], {
        x: 0.5, y: 1.2, w: 12.3, h: 5.8,
        barDir: "bar",
        chartColors: [PRIMARY],
        showValue: true,
        dataLabelFontFace: FONT,
        dataLabelFontSize: 11,
        catAxisLabelFontFace: FONT,
        catAxisLabelFontSize: 11,
        valAxisLabelFontFace: FONT,
        valAxisLabelFontSize: 10,
        showLegend: false,
      });
    } else {
      s.addText("No page data available for this period.", {
        x: 0.5, y: 3.5, w: 12, h: 0.5,
        ...bodyOpts, fontSize: 16, color: MUTED, align: "center",
      });
    }
  }

  // ── Slide 4: Top 5 keywords (table) ────────────────────────────────
  {
    const s = pptx.addSlide();
    s.addText("Top 5 Keywords", {
      x: 0.5, y: 0.3, w: 12, h: 0.6,
      ...titleOpts, fontSize: 28,
    });

    const top5 = report.wins.topKeywords.slice(0, 5);
    const header = ["Keyword", "Clicks", "Impressions", "CTR", "Position"];
    const headerRow = header.map((h) => ({
      text: h,
      options: {
        bold: true, color: WHITE, fill: { color: PRIMARY },
        fontFace: FONT, fontSize: 13, align: "center" as const,
      },
    }));

    if (top5.length > 0) {
      const rows: PptxGenJS.TableRow[] = [headerRow];
      top5.forEach((k, i) => {
        const bg = i % 2 === 0 ? WHITE : LIGHT;
        rows.push([
          { text: k.query, options: { fontFace: FONT, fontSize: 12, color: DARK, fill: { color: bg } } },
          { text: fmt(k.clicks), options: { fontFace: FONT, fontSize: 12, color: DARK, fill: { color: bg }, align: "right" } },
          { text: fmt(k.impressions), options: { fontFace: FONT, fontSize: 12, color: DARK, fill: { color: bg }, align: "right" } },
          { text: `${k.ctr.toFixed(1)}%`, options: { fontFace: FONT, fontSize: 12, color: DARK, fill: { color: bg }, align: "right" } },
          { text: k.position.toFixed(1), options: { fontFace: FONT, fontSize: 12, color: DARK, fill: { color: bg }, align: "right" } },
        ]);
      });
      s.addTable(rows, {
        x: 0.5, y: 1.2, w: 12.3,
        colW: [5.3, 1.75, 1.75, 1.75, 1.75],
        rowH: 0.55,
        border: { type: "solid", pt: 0.5, color: "E2E8F0" },
      });
    } else {
      s.addText("No keyword data available for this period.", {
        x: 0.5, y: 3.5, w: 12, h: 0.5,
        ...bodyOpts, fontSize: 16, color: MUTED, align: "center",
      });
    }
  }

  // ── Slide 5: Declining pages (red themed table) ────────────────────
  {
    const s = pptx.addSlide();
    s.addText("Declining Pages", {
      x: 0.5, y: 0.3, w: 12, h: 0.6,
      ...titleOpts, fontSize: 28, color: RED,
    });
    s.addText("Pages with ≥20% drop in clicks period over period.", {
      x: 0.5, y: 0.85, w: 12, h: 0.35,
      fontFace: FONT, fontSize: 12, color: MUTED,
    });

    const declines = report.declines.decliningPages.slice(0, 5);
    const header = ["Page", "Clicks", "Prev", "Change", "Position"];
    const headerRow = header.map((h) => ({
      text: h,
      options: {
        bold: true, color: WHITE, fill: { color: RED },
        fontFace: FONT, fontSize: 13, align: "center" as const,
      },
    }));

    if (declines.length > 0) {
      const rows: PptxGenJS.TableRow[] = [headerRow];
      declines.forEach((p, i) => {
        const bg = i % 2 === 0 ? WHITE : RED_BG;
        rows.push([
          { text: shortUrl(p.url, 60), options: { fontFace: FONT, fontSize: 11, color: DARK, fill: { color: bg } } },
          { text: fmt(p.clicks), options: { fontFace: FONT, fontSize: 11, color: DARK, fill: { color: bg }, align: "right" } },
          { text: fmt(p.previousClicks ?? 0), options: { fontFace: FONT, fontSize: 11, color: DARK, fill: { color: bg }, align: "right" } },
          { text: p.clicksChangePct != null ? `${p.clicksChangePct.toFixed(1)}%` : "—", options: { fontFace: FONT, fontSize: 11, color: RED, bold: true, fill: { color: bg }, align: "right" } },
          { text: p.position.toFixed(1), options: { fontFace: FONT, fontSize: 11, color: DARK, fill: { color: bg }, align: "right" } },
        ]);
      });
      s.addTable(rows, {
        x: 0.5, y: 1.4, w: 12.3,
        colW: [5.8, 1.5, 1.5, 1.75, 1.75],
        rowH: 0.55,
        border: { type: "solid", pt: 0.5, color: "FECACA" },
      });
    } else {
      s.addText("No declining pages this period — great news!", {
        x: 0.5, y: 3.5, w: 12, h: 0.5,
        ...bodyOpts, fontSize: 16, color: MUTED, align: "center",
      });
    }
  }

  // ── Slide 6: Recommendations ───────────────────────────────────────
  {
    const s = pptx.addSlide();
    s.addText("Top Recommendations", {
      x: 0.5, y: 0.3, w: 12, h: 0.6,
      ...titleOpts, fontSize: 28,
    });

    const recs = report.aiInsights.recommendations.slice(0, 5);
    if (recs.length > 0) {
      recs.forEach((rec, i) => {
        const y = 1.2 + i * 1.15;
        // Numbered circle
        s.addShape(pptx.ShapeType.ellipse, {
          x: 0.5, y, w: 0.7, h: 0.7,
          fill: { color: PRIMARY }, line: { color: PRIMARY },
        });
        s.addText(`${i + 1}`, {
          x: 0.5, y, w: 0.7, h: 0.7,
          fontFace: FONT, fontSize: 20, bold: true, color: WHITE, align: "center", valign: "middle",
        });
        s.addText(rec.title, {
          x: 1.4, y, w: 11.4, h: 0.4,
          fontFace: FONT, fontSize: 16, bold: true, color: DARK,
        });
        if (rec.description) {
          s.addText(rec.description, {
            x: 1.4, y: y + 0.4, w: 11.4, h: 0.65,
            fontFace: FONT, fontSize: 12, color: MUTED,
          });
        }
      });
    } else {
      s.addText("No AI recommendations available. Run an analysis to generate strategic insights.", {
        x: 0.5, y: 3.5, w: 12, h: 0.5,
        ...bodyOpts, fontSize: 16, color: MUTED, align: "center",
      });
    }
  }

  // ── Slide 7: Thank You ─────────────────────────────────────────────
  {
    const s = pptx.addSlide();
    s.background = { color: PRIMARY };
    s.addText("Thank You", {
      x: 0.7, y: 2.6, w: 12, h: 1.2,
      fontFace: FONT, fontSize: 60, bold: true, color: WHITE, align: "center",
    });
    s.addText(brand.name, {
      x: 0.7, y: 3.9, w: 12, h: 0.7,
      fontFace: FONT, fontSize: 26, color: WHITE, align: "center",
    });
    s.addText(brand.domain, {
      x: 0.7, y: 4.6, w: 12, h: 0.5,
      fontFace: FONT, fontSize: 16, color: WHITE, align: "center",
    });
  }

  const out = await pptx.write({ outputType: "nodebuffer" });
  return out as Buffer;
}
