/**
 * Generate samples/CapaKrakenExamples.xlsx from the live database.
 *
 * Run from repo root:
 *   pnpm --filter @capakraken/db db:excel
 */

import { PrismaClient } from "@prisma/client";
import ExcelJS from "exceljs";
import path from "path";
import { fileURLToPath } from "url";
import { loadWorkspaceEnv } from "./load-workspace-env.js";
import { assertCapaKrakenDbTarget } from "./safe-destructive-env.js";

loadWorkspaceEnv();
assertCapaKrakenDbTarget("db:excel");

const prisma = new PrismaClient();
const __dirname = path.dirname(fileURLToPath(import.meta.url));

// ─── Colour palette ──────────────────────────────────────────────────────────

const COLORS = {
  headerBg:       "FF1E3A5F",  // dark navy
  headerFg:       "FFFFFFFF",
  altRow:         "FFF5F7FA",
  border:         "FFCDD5E0",
  // status
  completed:      "FFD1FAE5",
  active:         "FFDBEAFE",
  onHold:         "FFFEF3C7",
  draft:          "FFF3F4F6",
  cancelled:      "FFFEE2E2",
  // allocation status
  allocActive:    "FFDBEAFE",
  allocConfirmed: "FFD1FAE5",
  allocProposed:  "FFFEF3C7",
  allocCompleted: "FFF3F4F6",
};

// ─── Helpers ─────────────────────────────────────────────────────────────────

function fmtDate(d: Date | null): string {
  if (!d) return "";
  return d.toISOString().split("T")[0]!;
}

function fmtCents(cents: number): number {
  return Math.round(cents) / 100;
}

type AnyRow = ExcelJS.Row;

function applyHeader(ws: ExcelJS.Worksheet, columns: ExcelJS.Column[]) {
  ws.columns = columns;
  const headerRow: AnyRow = ws.getRow(1);
  headerRow.eachCell((cell) => {
    cell.font   = { bold: true, color: { argb: COLORS.headerFg }, size: 10 };
    cell.fill   = { type: "pattern", pattern: "solid", fgColor: { argb: COLORS.headerBg } };
    cell.border = {
      bottom: { style: "thin", color: { argb: COLORS.border } },
    };
    cell.alignment = { vertical: "middle", horizontal: "center", wrapText: false };
  });
  headerRow.height = 22;
}

function styleDataRows(ws: ExcelJS.Worksheet, startRow: number, totalRows: number) {
  for (let r = startRow; r <= startRow + totalRows - 1; r++) {
    const row: AnyRow = ws.getRow(r);
    const isAlt = (r - startRow) % 2 === 1;
    row.eachCell({ includeEmpty: true }, (cell) => {
      if (isAlt) {
        cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: COLORS.altRow } };
      }
      cell.font      = { size: 10 };
      cell.alignment = { vertical: "middle" };
      cell.border    = {
        bottom: { style: "hair", color: { argb: COLORS.border } },
      };
    });
    row.height = 18;
  }
}

function highlightCell(cell: ExcelJS.Cell, argb: string) {
  cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: argb } };
}

function statusColor(status: string): string {
  switch (status) {
    case "COMPLETED":  return COLORS.completed;
    case "ACTIVE":     return COLORS.active;
    case "ON_HOLD":    return COLORS.onHold;
    case "DRAFT":      return COLORS.draft;
    case "CANCELLED":  return COLORS.cancelled;
    default:           return COLORS.draft;
  }
}

function allocStatusColor(status: string): string {
  switch (status) {
    case "ACTIVE":     return COLORS.allocActive;
    case "CONFIRMED":  return COLORS.allocConfirmed;
    case "PROPOSED":   return COLORS.allocProposed;
    case "COMPLETED":  return COLORS.allocCompleted;
    default:           return COLORS.draft;
  }
}

// ─── Sheet builders ───────────────────────────────────────────────────────────

async function buildResourcesSheet(wb: ExcelJS.Workbook) {
  const resources = await prisma.resource.findMany({ orderBy: { chapter: "asc" } });

  const ws = wb.addWorksheet("Resources", {
    views: [{ state: "frozen", ySplit: 1 }],
  });

  applyHeader(ws, [
    { header: "EID",             key: "eid",          width: 22 },
    { header: "Display Name",    key: "displayName",  width: 24 },
    { header: "Chapter",         key: "chapter",      width: 30 },
    { header: "Type of Work",    key: "typeOfWork",   width: 30 },
    { header: "City",            key: "city",         width: 16 },
    { header: "Employee Type",   key: "empType",      width: 16 },
    { header: "LCR (€/h)",      key: "lcr",          width: 12 },
    { header: "UCR (€/h)",      key: "ucr",          width: 12 },
    { header: "Chargeability %", key: "chargeability",width: 16 },
    { header: "Mon h",           key: "mon",          width: 8  },
    { header: "Tue h",           key: "tue",          width: 8  },
    { header: "Wed h",           key: "wed",          width: 8  },
    { header: "Thu h",           key: "thu",          width: 8  },
    { header: "Fri h",           key: "fri",          width: 8  },
    { header: "Skills",          key: "skills",       width: 40 },
  ] as ExcelJS.Column[]);

  let rowIdx = 2;
  for (const res of resources) {
    const avail = res.availability as {
      monday: number; tuesday: number; wednesday: number; thursday: number; friday: number;
    };
    const dynFields = res.dynamicFields as { workType?: string; city?: string; employeeType?: string };
    const skills = (res.skills as Array<{ skill: string; proficiency: number }> | null) ?? [];
    const skillStr = skills.map((s) => `${s.skill} (${s.proficiency})`).join(", ");

    const row: AnyRow = ws.getRow(rowIdx++);
    row.values = [
      res.eid,
      res.displayName,
      res.chapter,
      dynFields.workType ?? "",
      dynFields.city ?? "",
      dynFields.employeeType ?? "",
      fmtCents(res.lcrCents),
      fmtCents(res.ucrCents),
      Math.round(res.chargeabilityTarget),
      avail.monday,
      avail.tuesday,
      avail.wednesday,
      avail.thursday,
      avail.friday,
      skillStr,
    ];
    row.commit();
  }

  styleDataRows(ws, 2, resources.length);
  ws.autoFilter = { from: "A1", to: "O1" };
}

async function buildProjectsSheet(wb: ExcelJS.Workbook) {
  const projects = await prisma.project.findMany({ orderBy: { startDate: "asc" } });

  const ws = wb.addWorksheet("Projects", {
    views: [{ state: "frozen", ySplit: 1 }],
  });

  applyHeader(ws, [
    { header: "Short Code",      key: "code",        width: 14 },
    { header: "Name",            key: "name",        width: 46 },
    { header: "Client",          key: "client",      width: 14 },
    { header: "Order Type",      key: "orderType",   width: 14 },
    { header: "Alloc Type",      key: "allocType",   width: 12 },
    { header: "Status",          key: "status",      width: 14 },
    { header: "Start Date",      key: "startDate",   width: 14 },
    { header: "End Date",        key: "endDate",     width: 14 },
    { header: "Win Prob %",      key: "winProb",     width: 12 },
    { header: "Budget (€)",     key: "budget",      width: 16 },
    { header: "Responsible",     key: "responsible", width: 24 },
  ] as ExcelJS.Column[]);

  let rowIdx = 2;
  for (const proj of projects) {
    const dynFields = proj.dynamicFields as { clientUnit?: string };
    const row: AnyRow = ws.getRow(rowIdx);
    row.values = [
      proj.shortCode,
      proj.name,
      dynFields.clientUnit ?? "",
      proj.orderType,
      proj.allocationType,
      proj.status,
      fmtDate(proj.startDate),
      fmtDate(proj.endDate),
      proj.winProbability,
      fmtCents(proj.budgetCents),
      proj.responsiblePerson ?? "",
    ];
    row.commit();

    // Colour the Status cell
    highlightCell(row.getCell("status"), statusColor(proj.status));
    rowIdx++;
  }

  styleDataRows(ws, 2, projects.length);
  ws.autoFilter = { from: "A1", to: "K1" };
}

async function buildAllocationsSheet(wb: ExcelJS.Workbook) {
  const [assignments, demandRequirements] = await Promise.all([
    prisma.assignment.findMany({
      orderBy: [{ project: { startDate: "asc" } }, { resource: { displayName: "asc" } }],
      include: {
        resource: { select: { eid: true, displayName: true, chapter: true } },
        project: { select: { shortCode: true, name: true, startDate: true } },
      },
    }),
    prisma.demandRequirement.findMany({
      orderBy: [{ project: { startDate: "asc" } }, { role: "asc" }],
      include: {
        project: { select: { shortCode: true, name: true, startDate: true } },
      },
    }),
  ]);

  const allocations = [
    ...assignments.map((assignment) => ({
      projectStartDate: assignment.project.startDate,
      projectCode: assignment.project.shortCode,
      projectName: assignment.project.name,
      eid: assignment.resource?.eid ?? "",
      resourceName: assignment.resource?.displayName ?? "",
      chapter: assignment.resource?.chapter ?? "",
      role: assignment.role ?? "",
      startDate: assignment.startDate,
      endDate: assignment.endDate,
      hoursPerDay: assignment.hoursPerDay,
      dailyCostCents: assignment.dailyCostCents,
      status: assignment.status,
    })),
    ...demandRequirements.map((demandRequirement) => ({
      projectStartDate: demandRequirement.project.startDate,
      projectCode: demandRequirement.project.shortCode,
      projectName: demandRequirement.project.name,
      eid: "",
      resourceName: "",
      chapter: "",
      role: demandRequirement.role ?? "",
      startDate: demandRequirement.startDate,
      endDate: demandRequirement.endDate,
      hoursPerDay: demandRequirement.hoursPerDay,
      dailyCostCents: 0,
      status: demandRequirement.status,
    })),
  ].sort((left, right) => {
    const startDiff = left.projectStartDate.getTime() - right.projectStartDate.getTime();
    if (startDiff !== 0) {
      return startDiff;
    }

    const resourceDiff = left.resourceName.localeCompare(right.resourceName);
    if (resourceDiff !== 0) {
      return resourceDiff;
    }

    return left.role.localeCompare(right.role);
  });

  const ws = wb.addWorksheet("Allocations", {
    views: [{ state: "frozen", ySplit: 1 }],
  });

  applyHeader(ws, [
    { header: "Project Code",    key: "projCode",    width: 14 },
    { header: "Project Name",    key: "projName",    width: 40 },
    { header: "EID",             key: "eid",         width: 20 },
    { header: "Resource Name",   key: "resource",    width: 24 },
    { header: "Chapter",         key: "chapter",     width: 28 },
    { header: "Role",            key: "role",        width: 20 },
    { header: "Start Date",      key: "startDate",   width: 14 },
    { header: "End Date",        key: "endDate",     width: 14 },
    { header: "h/Day",           key: "hours",       width: 8  },
    { header: "Daily Cost (€)", key: "dailyCost",   width: 16 },
    { header: "Status",          key: "status",      width: 14 },
  ] as ExcelJS.Column[]);

  let rowIdx = 2;
  for (const alloc of allocations) {
    const row: AnyRow = ws.getRow(rowIdx);
    row.values = [
      alloc.projectCode,
      alloc.projectName,
      alloc.eid,
      alloc.resourceName,
      alloc.chapter,
      alloc.role,
      fmtDate(alloc.startDate),
      fmtDate(alloc.endDate),
      alloc.hoursPerDay,
      fmtCents(alloc.dailyCostCents),
      alloc.status,
    ];
    row.commit();

    highlightCell(row.getCell("status"), allocStatusColor(alloc.status));
    rowIdx++;
  }

  styleDataRows(ws, 2, allocations.length);
  ws.autoFilter = { from: "A1", to: "K1" };
}

async function buildSummarySheet(wb: ExcelJS.Workbook) {
  const [resourceCount, projectCount, assignmentCount, demandRequirementCount] = await Promise.all([
    prisma.resource.count(),
    prisma.project.count(),
    prisma.assignment.count(),
    prisma.demandRequirement.count(),
  ]);
  const allocationCount = assignmentCount + demandRequirementCount;

  const ws = wb.addWorksheet("Summary");
  ws.columns = [
    { key: "label", width: 30 },
    { key: "value", width: 20 },
  ] as ExcelJS.Column[];

  const title = ws.getCell("A1");
  title.value = "CapaKraken — Seed Data Summary";
  title.font  = { bold: true, size: 14, color: { argb: COLORS.headerBg } };
  ws.mergeCells("A1:B1");
  ws.getRow(1).height = 28;

  const generated = ws.getCell("A2");
  generated.value = `Generated: ${new Date().toISOString().split("T")[0]}`;
  generated.font  = { italic: true, size: 10, color: { argb: "FF666666" } };
  ws.mergeCells("A2:B2");
  ws.getRow(2).height = 18;

  const rows: [string, number | string][] = [
    ["Resources",   resourceCount],
    ["Projects",    projectCount],
    ["Allocations", allocationCount],
  ];

  rows.forEach(([label, value], i) => {
    const row = ws.getRow(4 + i);
    row.getCell(1).value = label;
    row.getCell(1).font  = { bold: true, size: 10 };
    row.getCell(2).value = value;
    row.getCell(2).font  = { size: 10 };
    row.height = 20;
  });
}

// ─── Entry point ─────────────────────────────────────────────────────────────

async function main() {
  console.log("Connecting to database...");

  const wb = new ExcelJS.Workbook();
  wb.creator  = "CapaKraken";
  wb.created  = new Date();
  wb.modified = new Date();

  console.log("Building sheets...");
  await buildSummarySheet(wb);
  await buildResourcesSheet(wb);
  await buildProjectsSheet(wb);
  await buildAllocationsSheet(wb);

  const outPath = path.resolve(__dirname, "../../../samples/CapaKrakenExamples.xlsx");
  await wb.xlsx.writeFile(outPath);
  console.log(`Excel written to: ${outPath}`);
}

main()
  .catch((e) => { console.error(e); process.exit(1); })
  .finally(() => prisma.$disconnect());
