'use client';

import { useState } from 'react';
import { Download, FileSpreadsheet, FileText, Sheet } from 'lucide-react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { defaultCsvFilename, exportReportAsCsv } from '@/lib/reports/exporters/csv';
import { defaultPdfFilename, exportReportAsPdf } from '@/lib/reports/exporters/pdf';
import { defaultXlsxFilename, exportReportAsXlsx } from '@/lib/reports/exporters/xlsx';
import type { ExportResult, ReportPayload } from '@/lib/reports/types';

/** Supported formats. Excel + PDF are scaffolded UI; only CSV is wired. */
type ExportFormat = 'csv' | 'xlsx' | 'pdf';

interface ReportExportButtonProps {
  /** Function that produces the ReportPayload at click time.
   *  Lazy: only invoked when the user picks a format, so building the
   *  payload (which may involve formatting numbers + dates from the
   *  live report state) doesn't run on every render. */
  buildPayload: () => ReportPayload;
  /** Disable the button (e.g. while the report query is loading). */
  disabled?: boolean;
}

/**
 * Shared export dropdown for every report. Three format options:
 *
 *  - CSV: working today via `papaparse`. Multi-section flat file.
 *  - Excel: scaffolded — wires through to the same payload but the
 *    `exportReportAsXlsx` implementation lands as Task #35.
 *  - PDF: scaffolded — same payload, branded shell wraps the output.
 *    Lands as Task #34.
 *
 * Format-disabled items render as disabled menu items with a "coming
 * soon" caption rather than being hidden, so the affordance is
 * discoverable across the platform from day one.
 */
export function ReportExportButton({ buildPayload, disabled }: ReportExportButtonProps) {
  const [exporting, setExporting] = useState(false);
  // Pending-format dialog state: when the user picks a format from the
  // dropdown, we capture that intent + open a rename dialog so they
  // can override the title (which is baked into both the filename AND
  // the document's header). The actual export fires from the dialog's
  // confirm button.
  const [pendingFormat, setPendingFormat] = useState<ExportFormat | null>(null);
  const [customTitle, setCustomTitle] = useState<string>('');

  function openRenameDialog(format: ExportFormat) {
    // Pre-fill with the current report's title so the user only types
    // when they want to override.
    try {
      const payload = buildPayload();
      setCustomTitle(payload.title);
      setPendingFormat(format);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Could not prepare export');
    }
  }

  async function handleConfirm() {
    if (!pendingFormat) return;
    setExporting(true);
    try {
      // Rebuild payload at export time so any background-state changes
      // (e.g. the rep just picked a different date range) are reflected.
      const basePayload = buildPayload();
      const trimmedTitle = customTitle.trim();
      const titleChanged = trimmedTitle && trimmedTitle !== basePayload.title;
      const titledPayload: ReportPayload = {
        ...basePayload,
        title: trimmedTitle || basePayload.title,
      };
      // When the user has CUSTOMISED the title, use it verbatim as the
      // filename (no auto-appended date suffix — they typed a meaningful
      // name, respect it). When they kept the default, fall back to the
      // exporter's standard `slug-fromdate_todate.<ext>` pattern so
      // historical downloads stay disambiguated.
      const filenameOverride = titleChanged
        ? `${slugify(trimmedTitle)}.${pendingFormat}`
        : undefined;

      let result: ExportResult;
      if (pendingFormat === 'csv') {
        result = exportReportAsCsv(titledPayload, { filenameOverride });
      } else if (pendingFormat === 'xlsx') {
        result = await exportReportAsXlsx(titledPayload, { filenameOverride });
      } else if (pendingFormat === 'pdf') {
        result = await exportReportAsPdf(titledPayload, { filenameOverride });
      } else {
        throw new Error(`${String(pendingFormat).toUpperCase()} export is not wired`);
      }
      downloadResult(result);
      toast.success(`Downloaded ${result.filename}`);
      setPendingFormat(null);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Export failed');
    } finally {
      setExporting(false);
    }
  }

  /**
   * Live filename preview for the dialog. Mirrors the same branching as
   * `handleConfirm` so what you see is what you get — custom title →
   * verbatim slug, default title → date-suffixed standard.
   */
  function previewFilename(): string {
    try {
      const base = buildPayload();
      const trimmed = customTitle.trim();
      const changed = trimmed && trimmed !== base.title;
      const ext = pendingFormat ?? 'csv';
      if (changed) {
        return `${slugify(trimmed) || 'report'}.${ext}`;
      }
      // Default pattern is exporter-specific.
      if (ext === 'csv') return defaultCsvFilename(base);
      if (ext === 'xlsx') return defaultXlsxFilename(base);
      if (ext === 'pdf') return defaultPdfFilename(base);
      return `${base.filenameSlug}-${todaySlug()}.${ext}`;
    } catch {
      return `report.${pendingFormat ?? 'csv'}`;
    }
  }

  return (
    <>
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <Button variant="outline" size="sm" disabled={disabled || exporting}>
            <Download className="mr-1.5 h-4 w-4" aria-hidden />
            Export
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end" className="w-56">
          <DropdownMenuLabel className="text-xs text-muted-foreground">
            Download report
          </DropdownMenuLabel>
          <DropdownMenuSeparator />
          <DropdownMenuItem onClick={() => openRenameDialog('csv')}>
            <FileText className="mr-2 h-4 w-4 text-muted-foreground" aria-hidden />
            <span className="flex-1">CSV</span>
          </DropdownMenuItem>
          <DropdownMenuItem onClick={() => openRenameDialog('xlsx')}>
            <FileSpreadsheet className="mr-2 h-4 w-4 text-muted-foreground" aria-hidden />
            <span className="flex-1">Excel</span>
          </DropdownMenuItem>
          <DropdownMenuItem onClick={() => openRenameDialog('pdf')}>
            <Sheet className="mr-2 h-4 w-4 text-muted-foreground" aria-hidden />
            <span className="flex-1">PDF</span>
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>

      <Dialog
        open={pendingFormat !== null}
        onOpenChange={(open) => {
          if (!open) setPendingFormat(null);
        }}
      >
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Name your export</DialogTitle>
            <DialogDescription>
              This title appears at the top of the file and is used as the filename. Leave it as- is
              for the default report name.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-2">
            <Label htmlFor="export-title-input" className="text-xs text-muted-foreground">
              Title
            </Label>
            <Input
              id="export-title-input"
              autoFocus
              value={customTitle}
              onChange={(e) => setCustomTitle(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === 'Enter' && !exporting) {
                  e.preventDefault();
                  handleConfirm();
                }
              }}
              placeholder="e.g. Q2 sales review for board"
            />
            <p className="text-[11px] text-muted-foreground">
              Filename: <code className="font-mono">{previewFilename()}</code>
            </p>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setPendingFormat(null)}
              disabled={exporting}
            >
              Cancel
            </Button>
            <Button size="sm" onClick={handleConfirm} disabled={exporting}>
              <Download className="mr-1.5 h-4 w-4" aria-hidden />
              {exporting ? 'Downloading…' : 'Download'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}

/**
 * File-safe slug from an arbitrary title. Lowercases, replaces runs
 * of non-alphanumerics with single hyphens, trims leading/trailing
 * hyphens. Cap at 80 chars so OS file dialogs don't get an essay.
 */
function slugify(s: string): string {
  return s
    .toLowerCase()
    .normalize('NFD')
    .replace(/[̀-ͯ]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 80);
}

function todaySlug(): string {
  return new Date().toISOString().slice(0, 10);
}

/**
 * Trigger a browser download for an ExportResult. The blob URL is
 * revoked after the click so we don't leak object URLs on long-lived
 * sessions where the user exports many reports.
 */
function downloadResult(result: ExportResult): void {
  const url = URL.createObjectURL(result.body);
  const a = document.createElement('a');
  a.href = url;
  a.download = result.filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}
