'use client';

import { useState, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@/components/ui/button';
import { DateTimePicker } from '@/components/ui/date-time-picker';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet';
import { ClientPicker } from '@/components/shared/client-picker';
import { InterestPicker } from '@/components/shared/interest-picker';
import { BerthPicker } from '@/components/shared/berth-picker';
import { YachtPicker } from '@/components/yachts/yacht-picker';
import { apiFetch } from '@/lib/api/client';
import { usePermissions } from '@/hooks/use-permissions';

/**
 * Format a Date as `YYYY-MM-DDTHH:MM` in the user's local timezone,
 * suitable for `<input type="datetime-local">`. Round-trip-safe with
 * `new Date(value)` (which parses as local when no TZ marker is
 * present). Replaces `iso.toISOString().slice(0,16)` which strips the
 * `Z` and silently mis-interprets UTC as local.
 */
function toLocalDatetimeLocal(d: Date): string {
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

/**
 * Build a Date relative to "now" for the quick-pick chips. Day-based
 * presets land on the user's preferred time-of-day (`digestTimeOfDay`
 * from user_profiles.preferences) - same source the default dueAt uses.
 * Hour-based presets use the current time + N hours.
 */
function buildPresetDate(
  preset:
    | { kind: 'hours'; hours: number }
    | { kind: 'tomorrow' }
    | { kind: 'in_days'; days: number }
    | { kind: 'next_monday' },
  timeOfDay: string | null,
): Date {
  const now = new Date();
  let h = 9;
  let m = 0;
  if (timeOfDay && /^\d{2}:\d{2}$/.test(timeOfDay)) {
    const [hh = '09', mm = '00'] = timeOfDay.split(':');
    const parsedH = Number.parseInt(hh, 10);
    const parsedM = Number.parseInt(mm, 10);
    if (Number.isFinite(parsedH) && parsedH >= 0 && parsedH <= 23) h = parsedH;
    if (Number.isFinite(parsedM) && parsedM >= 0 && parsedM <= 59) m = parsedM;
  }
  if (preset.kind === 'hours') {
    return new Date(now.getTime() + preset.hours * 60 * 60 * 1000);
  }
  if (preset.kind === 'tomorrow') {
    const t = new Date(now);
    t.setDate(t.getDate() + 1);
    t.setHours(h, m, 0, 0);
    return t;
  }
  if (preset.kind === 'in_days') {
    const t = new Date(now);
    t.setDate(t.getDate() + preset.days);
    t.setHours(h, m, 0, 0);
    return t;
  }
  // next_monday
  const t = new Date(now);
  const daysUntilMonday = (8 - t.getDay()) % 7 || 7;
  t.setDate(t.getDate() + daysUntilMonday);
  t.setHours(h, m, 0, 0);
  return t;
}

const DUE_PRESETS = [
  { label: 'In 1 hour', spec: { kind: 'hours', hours: 1 } as const },
  { label: 'In 4 hours', spec: { kind: 'hours', hours: 4 } as const },
  { label: 'Tomorrow', spec: { kind: 'tomorrow' } as const },
  { label: 'In 3 days', spec: { kind: 'in_days', days: 3 } as const },
  { label: 'Next week', spec: { kind: 'next_monday' } as const },
  { label: 'In 2 weeks', spec: { kind: 'in_days', days: 14 } as const },
] as const;

interface UserOption {
  id: string;
  displayName: string;
}

interface ReminderFormProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  reminder?: {
    id: string;
    title: string;
    note: string | null;
    dueAt: string;
    priority: string;
    assignedTo: string | null;
    clientId: string | null;
    interestId: string | null;
    berthId: string | null;
    yachtId: string | null;
  } | null;
  // Pre-fill entity link when creating from entity detail pages
  defaultClientId?: string;
  defaultInterestId?: string;
  defaultBerthId?: string;
  defaultYachtId?: string;
  onSuccess: () => void;
}

export function ReminderForm(props: ReminderFormProps) {
  // Key-based remount: the body is keyed on `open + reminder.id` so its
  // useState initializers re-run on each open with the correct seed.
  // Replaces the prior useEffect-driven open→reset that the Compiler
  // flagged as set-state-in-effect.
  return (
    <ReminderFormBody
      key={props.open ? `open:${props.reminder?.id ?? 'new'}` : 'closed'}
      {...props}
    />
  );
}

function ReminderFormBody({
  open,
  onOpenChange,
  reminder,
  defaultClientId,
  defaultInterestId,
  defaultBerthId,
  defaultYachtId,
  onSuccess,
}: ReminderFormProps) {
  const isEdit = !!reminder;
  // Phase 4 - load the rep's preferred default-reminder time (HH:MM)
  // BEFORE seeding the dueAt state. React Query's cache keeps this
  // available synchronously on subsequent dialog opens (staleTime 60s)
  // so the initial value is the rep's preference, not the historical
  // 09:00 fallback. Enabled only on create-mode opens - edit mode
  // already has the existing dueAt to seed from.
  const meQuery = useQuery<{ data: { preferences?: { digestTimeOfDay?: string } } }>({
    queryKey: ['me', 'preferences'],
    queryFn: () => apiFetch('/api/v1/me'),
    enabled: open && !reminder,
    staleTime: 60_000,
  });
  const userTodPref = meQuery.data?.data.preferences?.digestTimeOfDay ?? null;

  // Tomorrow 9am default for new-reminder dueAt.
  //
  // <input type="datetime-local"> takes/produces LOCAL wall-clock time
  // without a TZ marker. The naive round-trip (`iso.slice(0,16)` /
  // `toISOString().slice(0,16)`) subtracts the user's UTC offset on
  // every load+save cycle, drifting reminders backward by ~2h per save
  // in Warsaw (datetime-auditor C1). The helpers below build a local
  // YYYY-MM-DDTHH:MM string from the Date's getters and parse it back
  // with the user's offset preserved.
  const defaultDueAt = useMemo(() => {
    const t = new Date();
    t.setDate(t.getDate() + 1);
    // Honour the rep's user_profiles.preferences.digestTimeOfDay when
    // set ("HH:MM"). Falls back to 09:00 - historical default.
    let h = 9;
    let m = 0;
    if (userTodPref && /^\d{2}:\d{2}$/.test(userTodPref)) {
      const [hh = '09', mm = '00'] = userTodPref.split(':');
      const parsedH = Number.parseInt(hh, 10);
      const parsedM = Number.parseInt(mm, 10);
      if (Number.isFinite(parsedH) && parsedH >= 0 && parsedH <= 23) h = parsedH;
      if (Number.isFinite(parsedM) && parsedM >= 0 && parsedM <= 59) m = parsedM;
    }
    t.setHours(h, m, 0, 0);
    return toLocalDatetimeLocal(t);
  }, [userTodPref]);
  const [title, setTitle] = useState(reminder?.title ?? '');
  const [note, setNote] = useState(reminder?.note ?? '');
  const [dueAt, setDueAt] = useState(
    reminder ? toLocalDatetimeLocal(new Date(reminder.dueAt)) : defaultDueAt,
  );
  const [priority, setPriority] = useState(reminder?.priority ?? 'medium');
  const [assignedTo, setAssignedTo] = useState(reminder?.assignedTo ?? '');
  const [clientId, setClientId] = useState(reminder?.clientId ?? defaultClientId ?? '');
  const [interestId, setInterestId] = useState(reminder?.interestId ?? defaultInterestId ?? '');
  const [berthId, setBerthId] = useState(reminder?.berthId ?? defaultBerthId ?? '');
  const [yachtId, setYachtId] = useState(reminder?.yachtId ?? defaultYachtId ?? '');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const { can } = usePermissions();
  const canAssignOthers = can('reminders', 'assign_others');
  // useQuery replaces the prior useEffect(fetch+setState) pattern.
  const usersQuery = useQuery<{ data: UserOption[] }>({
    queryKey: ['admin', 'users', 'options'],
    queryFn: () => apiFetch('/api/v1/admin/users/options'),
    enabled: open && canAssignOthers,
  });
  const users = usersQuery.data?.data ?? [];

  // When a client is picked, restrict the YachtPicker to yachts owned by
  // that client OR by any company the client belongs to (e.g. a
  // managing-director client whose yachts are titled to the company).
  // Mirrors the interest-form pattern so the two surfaces stay
  // consistent.
  const clientDetailQuery = useQuery<{
    data: { companies?: Array<{ company: { id: string } }> };
  }>({
    queryKey: ['client-detail-for-reminder-form', clientId],
    queryFn: () => apiFetch(`/api/v1/clients/${clientId}`),
    enabled: !!clientId && open,
  });
  const memberCompanyIds: string[] =
    clientDetailQuery.data?.data.companies?.map((m) => m.company.id) ?? [];
  const yachtOwnerFilter = clientId
    ? [
        { type: 'client' as const, id: clientId },
        ...memberCompanyIds.map((id) => ({ type: 'company' as const, id })),
      ]
    : undefined;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    setLoading(true);

    try {
      const body = {
        title,
        note: note || undefined,
        dueAt: new Date(dueAt).toISOString(),
        priority,
        assignedTo: assignedTo || undefined,
        clientId: clientId || undefined,
        interestId: interestId || undefined,
        berthId: berthId || undefined,
        yachtId: yachtId || undefined,
      };

      if (isEdit) {
        await apiFetch(`/api/v1/reminders/${reminder.id}`, {
          method: 'PATCH',
          body,
        });
      } else {
        await apiFetch('/api/v1/reminders', {
          method: 'POST',
          body,
        });
      }
      onSuccess();
      onOpenChange(false);
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : 'Something went wrong';
      setError(message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent className="overflow-y-auto">
        <SheetHeader>
          <SheetTitle>{isEdit ? 'Edit reminder' : 'New reminder'}</SheetTitle>
          <p className="text-sm text-muted-foreground mt-2">
            Reminders are personal nudges - a follow-up call, a note to yourself, or something a
            teammate needs to action by a date. They show up in your dashboard, the daily digest
            email, and on whichever client / interest / berth you link them to.
          </p>
        </SheetHeader>

        <form onSubmit={handleSubmit} className="mt-6 space-y-4">
          <div className="space-y-2">
            <Label htmlFor="reminder-title">What&apos;s the reminder for?</Label>
            <Input
              id="reminder-title"
              value={title}
              onChange={(e) => setTitle(e.target.value)}
              placeholder="e.g. Follow up about EOI, Check insurance docs"
              required
            />
            <p className="text-xs text-muted-foreground">
              Short label so future-you knows what this is at a glance.
            </p>
          </div>

          <div className="space-y-2">
            <Label htmlFor="reminder-note">Note (optional)</Label>
            <Textarea
              id="reminder-note"
              value={note}
              onChange={(e) => setNote(e.target.value)}
              placeholder="Anything else you want to remember when this fires…"
              rows={3}
            />
          </div>

          {/* 2fr/1fr split  -  the datetime-local control needs more room
              for "MM/DD/YYYY HH:MM AM" than a 4-item priority Select. */}
          <div className="grid grid-cols-[2fr_1fr] gap-4">
            <div className="space-y-2">
              <Label htmlFor="reminder-due">Due Date & Time</Label>
              {/* Quick-pick chips. Same idiom as the snooze dialog so reps
                  don't have to think about month-day-time for the 80%
                  common cases. Each chip writes the formatted datetime
                  into the input, leaving the rep free to tweak. */}
              <div className="flex flex-wrap gap-1.5">
                {DUE_PRESETS.map((p) => (
                  <button
                    key={p.label}
                    type="button"
                    onClick={() =>
                      setDueAt(toLocalDatetimeLocal(buildPresetDate(p.spec, userTodPref)))
                    }
                    className="rounded-full border bg-background px-2.5 py-0.5 text-xs font-medium text-foreground transition-colors hover:bg-accent"
                  >
                    {p.label}
                  </button>
                ))}
              </div>
              <DateTimePicker
                id="reminder-due"
                value={dueAt}
                onChange={setDueAt}
                placeholder="Pick a due date and time"
              />
            </div>

            <div className="space-y-2">
              <Label htmlFor="reminder-priority">Priority</Label>
              <Select value={priority} onValueChange={setPriority}>
                <SelectTrigger id="reminder-priority">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="low">Low</SelectItem>
                  <SelectItem value="medium">Medium</SelectItem>
                  <SelectItem value="high">High</SelectItem>
                  <SelectItem value="urgent">Urgent</SelectItem>
                </SelectContent>
              </Select>
            </div>
          </div>

          {canAssignOthers && (
            <div className="space-y-2">
              <Label htmlFor="reminder-assign">Assign to user</Label>
              <Select
                value={assignedTo === '' ? '__self__' : assignedTo}
                onValueChange={(v) => setAssignedTo(v === '__self__' ? '' : v)}
              >
                <SelectTrigger id="reminder-assign">
                  <SelectValue placeholder="Myself" />
                </SelectTrigger>
                <SelectContent>
                  {/* Radix Select forbids empty-string values, so use a
                      sentinel here and map back to '' in the handler. */}
                  <SelectItem value="__self__">Myself</SelectItem>
                  {users.map((u) => (
                    <SelectItem key={u.id} value={u.id}>
                      {u.displayName}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          )}

          <div className="space-y-2">
            <Label className="text-xs text-muted-foreground">
              Attach to client / deal / berth / yacht
            </Label>
            <p className="text-xs text-muted-foreground">
              Linking a reminder pins it onto that record so anyone who opens the page sees it on
              the Reminders tab. Useful for &ldquo;chase this client for signed EOI&rdquo;,
              &ldquo;recheck B12 power capacity before contract&rdquo;, etc. Pick a client first to
              scope the interest and berth dropdowns to that client&apos;s deals. Leaving these
              blank keeps the reminder private to you on your dashboard only.
            </p>
            <div className="grid grid-cols-1 gap-2">
              <ClientPicker
                value={clientId || null}
                onChange={(id) => {
                  setClientId(id ?? '');
                  // Clearing the client also clears scoped selections so a
                  // stale interest/berth from a different client doesn't
                  // silently submit alongside the new client.
                  if (!id) {
                    setInterestId('');
                    setBerthId('');
                  }
                }}
              />
              <InterestPicker
                value={interestId || null}
                onChange={(id) => setInterestId(id ?? '')}
                clientId={clientId || null}
              />
              <BerthPicker
                value={berthId || null}
                onChange={(id) => setBerthId(id ?? '')}
                clientId={clientId || null}
              />
              <YachtPicker
                value={yachtId || null}
                onChange={(id) => setYachtId(id ?? '')}
                ownerFilter={yachtOwnerFilter}
                placeholder={clientId ? 'Yachts linked to client...' : 'Search yachts...'}
              />
            </div>
          </div>

          {error && <p className="text-sm text-destructive">{error}</p>}

          <SheetFooter>
            <Button
              type="button"
              variant="outline"
              onClick={() => onOpenChange(false)}
              disabled={loading}
            >
              Cancel
            </Button>
            <Button type="submit" disabled={loading || !title.trim() || !dueAt}>
              {loading ? 'Saving…' : isEdit ? 'Save changes' : 'Create Reminder'}
            </Button>
          </SheetFooter>
        </form>
      </SheetContent>
    </Sheet>
  );
}
