'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 { cn } from '@/lib/utils';
import { Checkbox } from '@/components/ui/checkbox';
import { DatePicker } from '@/components/ui/date-picker';
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,
  PDF_DASHBOARD_CATEGORY_LABELS,
  type PdfDashboardWidgetId,
  type PdfDashboardWidgetCategory,
} 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';

/**
 * Local-timezone YYYY-MM-DD formatter. We deliberately avoid
 * `toISOString().slice(0,10)` because it rolls through UTC and would
 * land on the previous day for any rep east of GMT after ~14:00 local.
 */
function toIsoLocal(d: Date): string {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${day}`;
}

/**
 * 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({ className }: { className?: string } = {}) {
  const { can } = usePermissions();
  const [open, setOpen] = useState(false);
  const [title, setTitle] = useState(`Report - ${new Date().toLocaleDateString('en-GB')}`);
  const [selected, setSelected] = useState<PdfDashboardWidgetId[]>(
    PDF_DASHBOARD_WIDGETS.map((w) => w.id),
  );
  // Default report window = last 30 days. Many of the new widgets
  // (period cohorts, occupancy timeline) require the window;
  // populating with sensible defaults means the rep gets a useful
  // report on first export without picking dates.
  const today = new Date();
  const last30 = new Date(today);
  last30.setDate(last30.getDate() - 30);
  const [dateFrom, setDateFrom] = useState(toIsoLocal(last30));
  const [dateTo, setDateTo] = useState(toIsoLocal(today));
  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() || 'Report',
      config: {
        kind: 'dashboard' as const,
        widgetIds: selected,
        ...(dateFrom ? { dateFrom } : {}),
        ...(dateTo ? { dateTo } : {}),
      },
    }),
    [title, selected, dateFrom, dateTo],
  );

  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() || 'Report',
          config: {
            kind: 'dashboard',
            widgetIds: selected,
            ...(dateFrom ? { dateFrom } : {}),
            ...(dateTo ? { dateTo } : {}),
          },
        }),
      });
      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="ghost"
        size="sm"
        onClick={() => setOpen(true)}
        title="Export dashboard as PDF"
        aria-label="Export dashboard as PDF"
        className={cn('h-9 w-9 p-0 text-muted-foreground hover:text-foreground', className)}
      >
        <FileDown className="h-4 w-4" aria-hidden />
      </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>
            {/* Date-range filter. Drives every time-period section
                (new clients in window, berths sold in window, occupancy
                timeline, etc.). Defaulted to the last 30 days so a
                first-time export already has a sensible window without
                the rep configuring anything. Sections that don't
                require a window (KPIs, current pipeline funnel, etc.)
                ignore it. */}
            <div className="space-y-1">
              <Label>Report window</Label>
              <div className="flex flex-wrap items-center gap-2">
                <DatePicker
                  id="export-date-from"
                  value={dateFrom}
                  onChange={setDateFrom}
                  placeholder="Start"
                  size="sm"
                  className="w-[150px]"
                />
                <span className="text-xs text-muted-foreground">→</span>
                <DatePicker
                  id="export-date-to"
                  value={dateTo}
                  onChange={setDateTo}
                  placeholder="End"
                  size="sm"
                  className="w-[150px]"
                />
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() => {
                    const t = new Date();
                    const start = new Date(t);
                    start.setDate(start.getDate() - 30);
                    setDateFrom(toIsoLocal(start));
                    setDateTo(toIsoLocal(t));
                  }}
                  className="h-8 text-xs"
                >
                  Last 30 days
                </Button>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() => {
                    const t = new Date();
                    const start = new Date(t);
                    start.setDate(start.getDate() - 90);
                    setDateFrom(toIsoLocal(start));
                    setDateTo(toIsoLocal(t));
                  }}
                  className="h-8 text-xs"
                >
                  Last 90 days
                </Button>
              </div>
              <p className="text-xs text-muted-foreground">
                Drives time-period sections (new clients, berths sold, occupancy timeline, etc.).
                Sections marked &ldquo;needs date range&rdquo; only render when both dates are set.
              </p>
            </div>
            <div className="space-y-2">
              <Label>Sections</Label>
              {/* Grouped checkbox list. Each widget knows its own
                  category; we render the categories in PDF_DASHBOARD_-
                  CATEGORY_LABELS' declared order so charts surface
                  before tables surface before period cohorts. */}
              <div className="max-h-[50vh] space-y-3 overflow-y-auto rounded-md border p-2">
                {(
                  Object.entries(PDF_DASHBOARD_CATEGORY_LABELS) as Array<
                    [PdfDashboardWidgetCategory, string]
                  >
                ).map(([category, label]) => {
                  const items = PDF_DASHBOARD_WIDGETS.filter((w) => w.category === category);
                  if (items.length === 0) return null;
                  return (
                    <div key={category} className="space-y-1">
                      <div className="px-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
                        {label}
                      </div>
                      <div className="space-y-0.5">
                        {items.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="flex items-center gap-1.5">
                                <span className="font-medium">{w.label}</span>
                                {w.isChart ? (
                                  <span className="rounded-full bg-primary/10 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-wide text-primary">
                                    chart
                                  </span>
                                ) : null}
                                {w.requiresPeriod ? (
                                  <span className="rounded-full bg-amber-100 px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-wide text-amber-800">
                                    needs date range
                                  </span>
                                ) : null}
                              </div>
                              <div className="text-xs text-muted-foreground">{w.description}</div>
                            </div>
                          </label>
                        ))}
                      </div>
                    </div>
                  );
                })}
              </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, '_') || 'report'}.pdf`}
          title={`Preview: ${title.trim() || 'Report'}`}
        />
      ) : null}
    </>
  );
}
