// Small helpers for exporting what is on the CURRENT screen as files.
// Everything here runs in the browser only - no backend calls.

// One table of data to export. Used for both CSV (a titled section)
// and XLSX (one worksheet).
export type ExportTable = {
  // Sheet name in Excel / section heading in CSV.
  title: string;
  // Column names, e.g. ["Agency", "Solved", "In Progress", "Total"].
  headers: string[];
  // One array per data row, in the same order as the headers.
  rows: (string | number)[][];
};

// Wraps a value in quotes when it contains a comma, quote, or line break,
// doubling any quotes inside it (the standard CSV escaping rule).
function escapeCsvValue(value: string | number): string {
  const text = String(value);
  const needsQuotes =
    text.includes(",") ||
    text.includes('"') ||
    text.includes("\n") ||
    text.includes("\r");
  return needsQuotes ? `"${text.replace(/"/g, '""')}"` : text;
}

// Builds one CSV file from one or more tables.
// With several tables, each section starts with its title and sections are
// separated by a blank line. With a single table we skip the title line so
// the first row is the header row (what Excel and most tools expect).
export function buildCsvBlob(tables: ExportTable[]): Blob {
  const lines: string[] = [];

  tables.forEach((table, tableIndex) => {
    if (tableIndex > 0) lines.push(""); // blank line between sections
    if (tables.length > 1) lines.push(escapeCsvValue(table.title));
    lines.push(table.headers.map(escapeCsvValue).join(","));
    for (const row of table.rows) {
      lines.push(row.map(escapeCsvValue).join(","));
    }
  });

  // "﻿" is the UTF-8 byte order mark. Without it, Excel shows Khmer
  // (and other non-Latin) text as garbage characters.
  return new Blob(["﻿" + lines.join("\r\n")], {
    type: "text/csv;charset=utf-8",
  });
}

// Excel forbids : \ / ? * [ ] in sheet names and caps them at 31 characters.
function toSafeSheetName(title: string): string {
  return title.replace(/[\\/?*:[\]]/g, " ").slice(0, 31) || "Sheet";
}

// Builds one .xlsx workbook with one worksheet per table.
// exceljs is a big library, so import() loads it only when the user actually
// exports - it never becomes part of the normal page bundle.
export async function buildXlsxBlob(tables: ExportTable[]): Promise<Blob> {
  const ExcelJS = await import("exceljs");
  const workbook = new ExcelJS.Workbook();

  for (const table of tables) {
    const sheet = workbook.addWorksheet(toSafeSheetName(table.title));

    // Setting `columns` writes the header row and sets each column's width.
    // Width = the longest value in that column, plus some breathing room.
    sheet.columns = table.headers.map((header, columnIndex) => {
      const longestCell = Math.max(
        header.length,
        ...table.rows.map((row) => String(row[columnIndex] ?? "").length),
      );
      return { header, width: Math.min(60, Math.max(12, longestCell + 4)) };
    });

    sheet.getRow(1).font = { bold: true }; // same style as the backend exports
    for (const row of table.rows) sheet.addRow(row);
  }

  const buffer = await workbook.xlsx.writeBuffer();
  return new Blob([new Uint8Array(buffer)], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  });
}

// Standard browser "save file" trick: point an invisible link at the blob,
// click it, then release the temporary URL. (Same approach as the existing
// table exports in working-group-issues-service.)
export function downloadBlob(blob: Blob, filename: string): void {
  const objectUrl = URL.createObjectURL(blob);
  const anchor = document.createElement("a");
  anchor.href = objectUrl;
  anchor.download = filename;
  anchor.click();
  URL.revokeObjectURL(objectUrl);
}

// Takes a picture of a piece of the page and downloads it as a PNG.
// `backgroundColor` fills the space behind rounded card corners, which
// would otherwise come out transparent.
export async function downloadNodeAsPng(
  node: HTMLElement,
  filename: string,
  backgroundColor: string,
): Promise<void> {
  const { toPng } = await import("html-to-image");
  // pixelRatio 2 = twice the on-screen resolution, so text stays sharp.
  const dataUrl = await toPng(node, { pixelRatio: 2, backgroundColor });
  const anchor = document.createElement("a");
  anchor.href = dataUrl;
  anchor.download = filename;
  anchor.click();
}

// Today as "2026-07-09" in the user's own timezone.
export function todayForFilename(): string {
  const now = new Date();
  const month = String(now.getMonth() + 1).padStart(2, "0");
  const day = String(now.getDate()).padStart(2, "0");
  return `${now.getFullYear()}-${month}-${day}`;
}
