'use client';

import { useMemo, useState } from 'react';
import { Eye, FileDown, Loader2 } from 'lucide-react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import {
  PDF_DASHBOARD_WIDGETS,
  type PdfDashboardWidgetId,
} from '@/lib/services/dashboard-report-widgets';
import { triggerBlobDownload } from '@/lib/utils/download';
import { usePermissions } from '@/hooks/use-permissions';
import { resolvePortIdFromSlug } from '@/lib/api/client';
import { SavedTemplatesPicker, type SavedTemplate } from './saved-templates-picker';
import { PdfPreviewModal } from './pdf-preview-modal';

/**
 * Dashboard "Export as PDF" affordance. Per-export dialog lets reps
 * pick which sections to include + set a custom title. Saved-template
 * support lands in Phase C; for now, the dialog defaults all widgets
 * checked + the current date in the title.
 *
 * Permission-gated client-side on `reports.export`; the server route
 * re-checks via withPermission so a tampered client can't bypass.
 */
export function ExportDashboardPdfButton() {
  const { can } = usePermissions();
  const [open, setOpen] = useState(false);
  const [title, setTitle] = useState(
    `Dashboard report — ${new Date().toLocaleDateString('en-GB')}`,
  );
  const [selected, setSelected] = useState<PdfDashboardWidgetId[]>(
    PDF_DASHBOARD_WIDGETS.map((w) => w.id),
  );
  const [loading, setLoading] = useState(false);
  const [previewOpen, setPreviewOpen] = useState(false);

  // Build the payload the modal will POST. useMemo keeps the
  // reference stable while the dialog's form is unchanged, so the
  // preview effect doesn't re-fire on unrelated re-renders.
  const previewPayload = useMemo(
    () => ({
      title: title.trim() || 'Dashboard report',
      config: { kind: 'dashboard' as const, widgetIds: selected },
    }),
    [title, selected],
  );

  if (!can('reports', 'export')) return null;

  function toggle(id: PdfDashboardWidgetId) {
    setSelected((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
  }

  async function handleExport() {
    if (selected.length === 0) {
      toast.error('Pick at least one section to include.');
      return;
    }
    setLoading(true);
    try {
      // FormData isn't required (this is a JSON body), but we DO need
      // to forward the X-Port-Id header so the server-side resolver
      // knows which port's data to use. apiFetch is JSON-only and
      // doesn't expose the raw response body; we need the buffer here
      // so do a raw fetch with the same header convention.
      const headers = new Headers({ 'Content-Type': 'application/json' });
      if (typeof window !== 'undefined') {
        const slug = window.location.pathname.split('/').filter(Boolean)[0];
        if (slug && slug !== 'login' && slug !== 'portal' && slug !== 'api') {
          const portId = await resolvePortIdFromSlug(slug);
          if (portId) headers.set('X-Port-Id', portId);
        }
      }
      const res = await fetch('/api/v1/reports/generate', {
        method: 'POST',
        headers,
        body: JSON.stringify({
          title: title.trim() || 'Dashboard report',
          config: {
            kind: 'dashboard',
            widgetIds: selected,
          },
        }),
      });
      if (!res.ok) {
        const text = await res.text();
        throw new Error(text || `Export failed (${res.status})`);
      }
      const blob = await res.blob();
      const filename = title.trim().replace(/[\\/]/g, '_') + '.pdf';
      triggerBlobDownload(blob, filename);
      toast.success('Report downloaded');
      setOpen(false);
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Export failed');
    } finally {
      setLoading(false);
    }
  }

  return (
    <>
      <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
        <FileDown className="mr-1.5 h-4 w-4" aria-hidden />
        Export PDF
      </Button>
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Export dashboard as PDF</DialogTitle>
            <DialogDescription>
              Pick which sections to include and set a title. The PDF inherits the active
              port&apos;s logo and primary color.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            <SavedTemplatesPicker
              kind="dashboard"
              currentConfig={{ widgetIds: selected }}
              onApply={(t: SavedTemplate) => {
                const cfg = t.config as { widgetIds?: string[] };
                if (Array.isArray(cfg.widgetIds)) {
                  setSelected(
                    cfg.widgetIds.filter((id): id is PdfDashboardWidgetId =>
                      PDF_DASHBOARD_WIDGETS.some((w) => w.id === id),
                    ),
                  );
                }
                if (t.name) setTitle(t.name);
              }}
            />
            <div className="space-y-1">
              <Label htmlFor="export-title">Title</Label>
              <Input id="export-title" value={title} onChange={(e) => setTitle(e.target.value)} />
            </div>
            <div className="space-y-2">
              <Label>Sections</Label>
              <div className="space-y-1.5 rounded-md border p-2">
                {PDF_DASHBOARD_WIDGETS.map((w) => (
                  <label
                    key={w.id}
                    className="flex items-start gap-2 cursor-pointer rounded-sm p-1 hover:bg-muted/50"
                  >
                    <Checkbox
                      checked={selected.includes(w.id)}
                      onCheckedChange={() => toggle(w.id)}
                      aria-label={w.label}
                    />
                    <div className="text-sm leading-tight">
                      <div className="font-medium">{w.label}</div>
                      <div className="text-xs text-muted-foreground">{w.description}</div>
                    </div>
                  </label>
                ))}
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setOpen(false)} disabled={loading}>
              Cancel
            </Button>
            <Button
              variant="outline"
              onClick={() => setPreviewOpen(true)}
              disabled={loading || selected.length === 0}
            >
              <Eye className="mr-1.5 h-4 w-4" aria-hidden />
              Preview
            </Button>
            <Button onClick={handleExport} disabled={loading || selected.length === 0}>
              {loading ? (
                <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />
              ) : (
                <FileDown className="mr-1.5 h-4 w-4" aria-hidden />
              )}
              Download PDF
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      {previewOpen ? (
        <PdfPreviewModal
          open
          onOpenChange={setPreviewOpen}
          payload={previewPayload}
          filename={`${title.trim().replace(/[\\/]/g, '_') || 'dashboard-report'}.pdf`}
          title={`Preview: ${title.trim() || 'Dashboard report'}`}
        />
      ) : null}
    </>
  );
}
