'use client';

import { useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Loader2, Plus, Save, X } 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 {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import type { ReportSchedule, ReportTemplate } from '@/lib/db/schema/reports';

type Cadence = 'weekly_monday_9' | 'monthly_first_9' | 'quarterly_first_9';
type OutputFormat = 'pdf' | 'csv' | 'png';

const CADENCE_OPTIONS: ReadonlyArray<{ value: Cadence; label: string }> = [
  { value: 'weekly_monday_9', label: 'Weekly · Monday 9:00 UTC' },
  { value: 'monthly_first_9', label: 'Monthly · 1st of month 9:00 UTC' },
  { value: 'quarterly_first_9', label: 'Quarterly · 1st of quarter 9:00 UTC' },
];

interface Props {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** When set, the dialog edits an existing schedule. Otherwise create. */
  schedule?: ReportSchedule;
  /** Pre-select a template for the create flow (e.g. when the user
   *  triggered the dialog from a specific template detail page). */
  initialTemplateId?: string;
}

interface Recipient {
  name: string;
  email: string;
}

/**
 * Outer dialog shell — owns the open/close state and re-mounts the
 * form body whenever the user switches between create / edit-N. The
 * `key` on `<ScheduleDialogForm>` resets every useState initializer
 * naturally when the schedule prop changes, sidestepping the
 * "setState in useEffect" anti-pattern an explicit reset effect
 * would otherwise need.
 */
export function ScheduleDialog({ open, onOpenChange, schedule, initialTemplateId }: Props) {
  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      {open ? (
        <ScheduleDialogForm
          key={schedule?.id ?? 'new'}
          schedule={schedule}
          initialTemplateId={initialTemplateId}
          onClose={() => onOpenChange(false)}
        />
      ) : null}
    </Dialog>
  );
}

interface FormProps {
  schedule?: ReportSchedule;
  initialTemplateId?: string;
  onClose: () => void;
}

function ScheduleDialogForm({ schedule, initialTemplateId, onClose }: FormProps) {
  const qc = useQueryClient();
  const isEdit = !!schedule;

  const [templateId, setTemplateId] = useState<string>(
    schedule?.templateId ?? initialTemplateId ?? '',
  );
  const [cadence, setCadence] = useState<Cadence>(
    (schedule?.cadence as Cadence) ?? 'weekly_monday_9',
  );
  const [outputFormat, setOutputFormat] = useState<OutputFormat>(
    (schedule?.outputFormat as OutputFormat) ?? 'pdf',
  );
  const [enabled, setEnabled] = useState<boolean>(schedule?.enabled ?? true);
  const [recipients, setRecipients] = useState<Recipient[]>(
    schedule?.recipients?.map((r) => ({ name: r.name ?? '', email: r.email })) ?? [],
  );
  const [newName, setNewName] = useState('');
  const [newEmail, setNewEmail] = useState('');

  // No `enabled` gate needed — the outer ScheduleDialog only mounts
  // this form when `open=true`, so the query is implicitly off until
  // the dialog actually appears.
  const templatesQuery = useQuery<{ data: ReportTemplate[] }>({
    queryKey: ['report-templates', 'all'],
    queryFn: () => apiFetch<{ data: ReportTemplate[] }>(`/api/v1/reports/templates`),
    staleTime: 30_000,
  });

  const createMutation = useMutation({
    mutationFn: async () =>
      apiFetch<{ data: ReportSchedule }>(`/api/v1/reports/schedules`, {
        method: 'POST',
        body: {
          templateId,
          cadence,
          outputFormat,
          enabled,
          recipients: recipients.map((r) => ({
            name: r.name.trim() || undefined,
            email: r.email.trim(),
          })),
        },
      }),
    onSuccess: () => {
      toast.success('Schedule created');
      void qc.invalidateQueries({ queryKey: ['report-schedules'] });
      onClose();
    },
    onError: (err) => toastError(err),
  });

  const updateMutation = useMutation({
    mutationFn: async () => {
      if (!schedule) throw new Error('No schedule to update');
      return apiFetch<{ data: ReportSchedule }>(`/api/v1/reports/schedules/${schedule.id}`, {
        method: 'PATCH',
        body: {
          cadence,
          outputFormat,
          enabled,
          recipients: recipients.map((r) => ({
            name: r.name.trim() || undefined,
            email: r.email.trim(),
          })),
        },
      });
    },
    onSuccess: () => {
      toast.success('Schedule updated');
      void qc.invalidateQueries({ queryKey: ['report-schedules'] });
      onClose();
    },
    onError: (err) => toastError(err),
  });

  function addRecipient() {
    const email = newEmail.trim();
    if (!email) return;
    setRecipients((prev) => [...prev, { name: newName.trim(), email }]);
    setNewName('');
    setNewEmail('');
  }

  function removeRecipient(idx: number) {
    setRecipients((prev) => prev.filter((_, i) => i !== idx));
  }

  const submitting = createMutation.isPending || updateMutation.isPending;
  const canSubmit = templateId !== '' && !submitting;
  const templates = templatesQuery.data?.data ?? [];

  return (
    <>
      <DialogContent className="sm:max-w-lg">
        <DialogHeader>
          <DialogTitle>{isEdit ? 'Edit schedule' : 'New schedule'}</DialogTitle>
          <DialogDescription>
            Recurring report. Recipients are optional — schedules with no recipients still run and
            appear in the runs history, they just skip the email step.
          </DialogDescription>
        </DialogHeader>

        <div className="space-y-4">
          <div className="space-y-1.5">
            <Label htmlFor="schedule-template" className="text-xs">
              Template
            </Label>
            <Select
              value={templateId}
              onValueChange={setTemplateId}
              disabled={isEdit || templatesQuery.isLoading}
            >
              <SelectTrigger id="schedule-template">
                <SelectValue
                  placeholder={
                    templatesQuery.isLoading
                      ? 'Loading templates…'
                      : templates.length === 0
                        ? 'No templates available — save one first'
                        : 'Pick a template'
                  }
                />
              </SelectTrigger>
              <SelectContent>
                {templates.map((t) => (
                  <SelectItem key={t.id} value={t.id}>
                    {t.name} <span className="text-muted-foreground">· {t.kind}</span>
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            {isEdit ? (
              <p className="text-[11px] text-muted-foreground">
                Template can&apos;t be changed on an existing schedule. Delete + recreate to
                re-bind.
              </p>
            ) : null}
          </div>

          <div className="grid grid-cols-2 gap-3">
            <div className="space-y-1.5">
              <Label htmlFor="schedule-cadence" className="text-xs">
                Cadence
              </Label>
              <Select value={cadence} onValueChange={(v) => setCadence(v as Cadence)}>
                <SelectTrigger id="schedule-cadence">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  {CADENCE_OPTIONS.map((c) => (
                    <SelectItem key={c.value} value={c.value}>
                      {c.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="space-y-1.5">
              <Label htmlFor="schedule-format" className="text-xs">
                Output
              </Label>
              <Select
                value={outputFormat}
                onValueChange={(v) => setOutputFormat(v as OutputFormat)}
              >
                <SelectTrigger id="schedule-format">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="pdf">PDF</SelectItem>
                </SelectContent>
              </Select>
              <p className="text-[11px] text-muted-foreground">
                CSV/XLSX coming for scheduled runs — use Export for those formats now.
              </p>
            </div>
          </div>

          <div className="space-y-2">
            <Label className="text-xs">Recipients (optional)</Label>
            <div className="space-y-1.5">
              {recipients.length === 0 ? (
                <p className="text-[11px] text-muted-foreground">
                  No recipients yet — runs will be archived but not emailed.
                </p>
              ) : (
                recipients.map((r, idx) => (
                  <div
                    key={`${r.email}-${idx}`}
                    className="flex items-center gap-2 rounded-md border bg-muted/30 px-2 py-1 text-sm"
                  >
                    <div className="flex-1">
                      <span className="font-medium">{r.name || r.email}</span>
                      {r.name ? (
                        <span className="ml-2 text-xs text-muted-foreground">{r.email}</span>
                      ) : null}
                    </div>
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      className="h-7 w-7"
                      onClick={() => removeRecipient(idx)}
                      aria-label="Remove recipient"
                    >
                      <X className="h-3.5 w-3.5" aria-hidden />
                    </Button>
                  </div>
                ))
              )}
            </div>
            <div className="grid grid-cols-[1fr_1.4fr_auto] gap-2">
              <Input
                placeholder="Name (optional)"
                value={newName}
                onChange={(e) => setNewName(e.target.value)}
                className="h-9"
              />
              <Input
                type="email"
                placeholder="email@example.com"
                value={newEmail}
                onChange={(e) => setNewEmail(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    e.preventDefault();
                    addRecipient();
                  }
                }}
                className="h-9"
              />
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={addRecipient}
                disabled={!newEmail.trim()}
              >
                <Plus className="mr-1.5 h-4 w-4" aria-hidden />
                Add
              </Button>
            </div>
          </div>

          <div className="flex items-center gap-2">
            <Switch id="schedule-enabled" checked={enabled} onCheckedChange={setEnabled} />
            <Label htmlFor="schedule-enabled" className="cursor-pointer text-sm">
              Enabled
            </Label>
          </div>
        </div>

        <DialogFooter>
          <Button variant="outline" size="sm" onClick={onClose} disabled={submitting}>
            Cancel
          </Button>
          <Button
            size="sm"
            onClick={() => (isEdit ? updateMutation.mutate() : createMutation.mutate())}
            disabled={!canSubmit}
          >
            {submitting ? (
              <Loader2 className="mr-1.5 h-4 w-4 animate-spin" aria-hidden />
            ) : (
              <Save className="mr-1.5 h-4 w-4" aria-hidden />
            )}
            {isEdit ? 'Save changes' : 'Create schedule'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </>
  );
}
