import Papa from 'papaparse';

import type { ExportResult, ReportPayload, ReportSection } from '@/lib/reports/types';

/**
 * Serialise a ReportPayload as CSV. The single-file output contains:
 *
 *  1. A title row + period row + generated-at row (header)
 *  2. A "KPIs" section with two columns (label, value)
 *  3. Each ReportSection's title, header row, data rows
 *  4. Blank lines between sections so Excel/Numbers can detect them
 *     when "Convert Text to Columns" is run after a paste.
 *
 * The output is plain UTF-8 with a leading BOM so Excel correctly
 * decodes non-ASCII characters (€ symbols, accented names, etc.)
 * without the user having to manually pick an encoding.
 */
interface CsvExportOptions {
  /** Override the auto-derived filename (which is
   *  `${payload.filenameSlug}-${date-range}.csv`). When the user has
   *  given the export a custom title, pass `${slugify(title)}.csv`
   *  here so the filename matches their intent without the verbose
   *  date suffix. */
  filenameOverride?: string;
}

export function exportReportAsCsv(
  payload: ReportPayload,
  options: CsvExportOptions = {},
): ExportResult {
  const lines: string[] = [];

  // Header
  lines.push(`"${escape(payload.title)}"`);
  lines.push(
    `"Period","${payload.range.from.toISOString().slice(0, 10)}","to","${payload.range.to
      .toISOString()
      .slice(0, 10)}"`,
  );
  lines.push(`"Generated","${new Date().toISOString()}"`);
  lines.push('');

  // KPI section
  if (payload.kpis.length > 0) {
    lines.push('"KPIs"');
    lines.push(
      Papa.unparse({
        fields: ['Metric', 'Value', 'Hint'],
        data: payload.kpis.map((k) => [k.label, formatValue(k.value), k.hint ?? '']),
      }),
    );
    lines.push('');
  }

  // Per-section blocks
  for (const section of payload.sections) {
    lines.push(`"${escape(section.title)}"`);
    lines.push(sectionToCsv(section));
    lines.push('');
  }

  // BOM + UTF-8 so Excel decodes correctly without prompting.
  const bom = '﻿';
  const body = new Blob([bom + lines.join('\n')], { type: 'text/csv;charset=utf-8' });

  return {
    filename: options.filenameOverride ?? `${payload.filenameSlug}-${dateSlug(payload.range)}.csv`,
    mimeType: 'text/csv;charset=utf-8',
    body,
  };
}

/** Reusable filename derivation so the UI's "filename preview" matches
 *  what the exporter will actually emit. */
export function defaultCsvFilename(payload: ReportPayload): string {
  return `${payload.filenameSlug}-${dateSlug(payload.range)}.csv`;
}

function sectionToCsv(section: ReportSection): string {
  return Papa.unparse({
    fields: section.columns.map((c) => c.label),
    data: section.rows.map((row) =>
      section.columns.map((c) => {
        const v = row[c.key];
        return c.format ? c.format(v) : formatValue(v);
      }),
    ),
  });
}

function formatValue(v: unknown): string {
  if (v === null || v === undefined) return '';
  if (v instanceof Date) return v.toISOString();
  if (typeof v === 'number') return String(v);
  return String(v);
}

function escape(s: string): string {
  return s.replace(/"/g, '""');
}

function dateSlug(range: { from: Date; to: Date }): string {
  return `${range.from.toISOString().slice(0, 10)}_${range.to.toISOString().slice(0, 10)}`;
}
