'use client';

import { useEffect, useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Bookmark, Check, Loader2, Save, Trash2 } 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 { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import { Textarea } from '@/components/ui/textarea';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import type { ReportTemplate } from '@/lib/db/schema/reports';

type StandaloneReportKind = 'sales' | 'operational' | 'financial' | 'marketing' | 'custom';

interface ListResponse {
  data: ReportTemplate[];
}

interface ReportTemplatesButtonProps<TConfig extends Record<string, unknown>> {
  /** Discriminator on the saved template row. Must match the report
   *  page; cross-kind templates are filtered out of the dropdown. */
  kind: StandaloneReportKind;
  /** Snapshot of the report's current view state. Save flows persist
   *  this verbatim; Load flows hand it back via onApply. */
  currentConfig: TConfig;
  /** Apply a loaded config to the report's local state. The component
   *  passes the entire `config` object back; the report client picks
   *  off whatever keys it knows about. */
  onApply: (config: TConfig) => void;
  /** Set after a load so the UI can show "Using template X". When the
   *  user changes any view-state (range, filter, etc.) downstream of
   *  load, the parent should null this back out so the badge clears. */
  activeTemplateId?: string | null;
  /** Optional callback so the parent can reflect template-load /
   *  template-clear in URL state. */
  onActiveTemplateChange?: (id: string | null) => void;
  /** Optional pre-selection: if the URL carried a `?templateId=…`,
   *  pass it in here and the component will hydrate + apply on mount. */
  initialTemplateId?: string | null;
}

/**
 * Combined Save + Load + Delete control for the standalone Sales and
 * Operational reports. One trigger button (with a "Using template X"
 * indicator), opens a popover that lists saved templates and offers
 * "Save as new template…".
 *
 * Schema: report_templates rows with kind ∈ {sales, operational}.
 * Config payload shape is owner-defined per report.
 */
export function ReportTemplatesButton<TConfig extends Record<string, unknown>>({
  kind,
  currentConfig,
  onApply,
  activeTemplateId,
  onActiveTemplateChange,
  initialTemplateId,
}: ReportTemplatesButtonProps<TConfig>) {
  const qc = useQueryClient();
  const [popoverOpen, setPopoverOpen] = useState(false);
  const [saveDialogOpen, setSaveDialogOpen] = useState(false);
  const [saveName, setSaveName] = useState('');
  const [saveDescription, setSaveDescription] = useState('');
  // Ref instead of state for the one-time hydration guard so we can
  // update it without triggering a re-render (and without tripping
  // react-hooks/set-state-in-effect on the surrounding useEffect).
  const hydratedRef = useRef(false);

  const listQuery = useQuery<ListResponse>({
    queryKey: ['report-templates', kind],
    queryFn: () =>
      apiFetch<ListResponse>(`/api/v1/reports/templates?kind=${encodeURIComponent(kind)}`),
    staleTime: 30_000,
  });

  // Hydrate from ?templateId=… on first render once the list lands.
  useEffect(() => {
    if (hydratedRef.current) return;
    if (!initialTemplateId) return;
    if (!listQuery.data) return;
    const found = listQuery.data.data.find((t) => t.id === initialTemplateId);
    if (found) {
      onApply(found.config as TConfig);
      onActiveTemplateChange?.(found.id);
    }
    hydratedRef.current = true;
  }, [initialTemplateId, listQuery.data, onApply, onActiveTemplateChange]);

  const saveMutation = useMutation({
    mutationFn: async (input: { name: string; description: string | null }) => {
      const body = {
        kind,
        name: input.name,
        description: input.description,
        // The schema-level `config.kind` cross-check on the API requires
        // the discriminator to live on the payload itself.
        config: { ...currentConfig, kind },
      };
      return apiFetch<{ data: ReportTemplate }>(`/api/v1/reports/templates`, {
        method: 'POST',
        body,
      });
    },
    onSuccess: ({ data }) => {
      toast.success(`Template "${data.name}" saved`);
      setSaveDialogOpen(false);
      setSaveName('');
      setSaveDescription('');
      onActiveTemplateChange?.(data.id);
      void qc.invalidateQueries({ queryKey: ['report-templates', kind] });
    },
    onError: (err) => toastError(err),
  });

  const deleteMutation = useMutation({
    mutationFn: async (id: string) => {
      await apiFetch(`/api/v1/reports/templates/${id}`, { method: 'DELETE' });
    },
    onSuccess: (_, id) => {
      toast.success('Template deleted');
      if (activeTemplateId === id) onActiveTemplateChange?.(null);
      void qc.invalidateQueries({ queryKey: ['report-templates', kind] });
    },
    onError: (err) => toastError(err),
  });

  const updateMutation = useMutation({
    mutationFn: async (id: string) => {
      return apiFetch<{ data: ReportTemplate }>(`/api/v1/reports/templates/${id}`, {
        method: 'PATCH',
        body: { config: { ...currentConfig, kind } },
      });
    },
    onSuccess: ({ data }) => {
      toast.success(`Template "${data.name}" updated`);
      void qc.invalidateQueries({ queryKey: ['report-templates', kind] });
    },
    onError: (err) => toastError(err),
  });

  function handleApply(template: ReportTemplate) {
    onApply(template.config as TConfig);
    onActiveTemplateChange?.(template.id);
    setPopoverOpen(false);
  }

  const templates = listQuery.data?.data ?? [];
  const activeTemplate = activeTemplateId
    ? templates.find((t) => t.id === activeTemplateId)
    : undefined;

  return (
    <>
      <Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
        <PopoverTrigger asChild>
          <Button variant="outline" size="sm">
            <Bookmark className="mr-1.5 h-4 w-4" aria-hidden />
            {activeTemplate ? `Template: ${activeTemplate.name}` : 'Templates'}
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-80 p-3" align="end">
          <div className="space-y-3">
            <div>
              <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                Saved templates
              </p>
              {listQuery.isLoading ? (
                <p className="mt-1 text-xs text-muted-foreground">Loading…</p>
              ) : templates.length === 0 ? (
                <p className="mt-1 text-xs text-muted-foreground">
                  No saved templates yet. Save your current view below.
                </p>
              ) : (
                <ul className="mt-1 max-h-56 overflow-y-auto space-y-0.5">
                  {templates.map((t) => {
                    const isActive = t.id === activeTemplateId;
                    return (
                      <li
                        key={t.id}
                        className="group flex items-center gap-1 rounded-sm px-1 py-0.5 hover:bg-muted/50"
                      >
                        <button
                          type="button"
                          onClick={() => handleApply(t)}
                          className="flex-1 text-left text-sm"
                        >
                          <span className="flex items-center gap-1.5">
                            {isActive ? (
                              <Check className="h-3.5 w-3.5 text-primary" aria-hidden />
                            ) : (
                              <span className="h-3.5 w-3.5" aria-hidden />
                            )}
                            <span>{t.name}</span>
                          </span>
                          {t.description ? (
                            <p className="pl-5 text-[11px] text-muted-foreground line-clamp-1">
                              {t.description}
                            </p>
                          ) : null}
                        </button>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-7 w-7 opacity-0 group-hover:opacity-100"
                          onClick={() => deleteMutation.mutate(t.id)}
                          disabled={deleteMutation.isPending}
                          aria-label={`Delete template ${t.name}`}
                          title="Delete this template"
                        >
                          <Trash2 className="h-3.5 w-3.5 text-destructive" aria-hidden />
                        </Button>
                      </li>
                    );
                  })}
                </ul>
              )}
            </div>
            <Separator />
            <div className="space-y-1.5">
              <Button
                type="button"
                variant="ghost"
                size="sm"
                className="w-full justify-start"
                onClick={() => {
                  setPopoverOpen(false);
                  setSaveDialogOpen(true);
                }}
              >
                <Save className="mr-1.5 h-4 w-4" aria-hidden />
                Save current view as template…
              </Button>
              {activeTemplate ? (
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="w-full justify-start"
                  onClick={() => {
                    updateMutation.mutate(activeTemplate.id);
                    setPopoverOpen(false);
                  }}
                  disabled={updateMutation.isPending}
                >
                  {updateMutation.isPending ? (
                    <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />
                  ) : (
                    <Save className="mr-1.5 h-4 w-4" aria-hidden />
                  )}
                  Update &quot;{activeTemplate.name}&quot;
                </Button>
              ) : null}
            </div>
          </div>
        </PopoverContent>
      </Popover>

      <Dialog open={saveDialogOpen} onOpenChange={setSaveDialogOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Save report as template</DialogTitle>
            <DialogDescription>
              The current date range and filter selection are captured. Re-run the report from this
              template in one click from the Reports landing page or the Templates list.
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-3">
            <div className="space-y-1">
              <Label htmlFor="template-name" className="text-xs">
                Name
              </Label>
              <Input
                id="template-name"
                autoFocus
                value={saveName}
                onChange={(e) => setSaveName(e.target.value)}
                placeholder="e.g. Monthly board sales view"
              />
            </div>
            <div className="space-y-1">
              <Label htmlFor="template-description" className="text-xs">
                Description (optional)
              </Label>
              <Textarea
                id="template-description"
                value={saveDescription}
                onChange={(e) => setSaveDescription(e.target.value)}
                placeholder="Helpful note about what this template is for"
                rows={2}
              />
            </div>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              size="sm"
              onClick={() => setSaveDialogOpen(false)}
              disabled={saveMutation.isPending}
            >
              Cancel
            </Button>
            <Button
              size="sm"
              onClick={() =>
                saveMutation.mutate({
                  name: saveName.trim(),
                  description: saveDescription.trim() || null,
                })
              }
              disabled={!saveName.trim() || saveMutation.isPending}
            >
              {saveMutation.isPending ? (
                <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />
              ) : (
                <Save className="mr-1.5 h-4 w-4" aria-hidden />
              )}
              Save template
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
