'use client';

import { useEffect, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Loader2, ChevronsUpDown, Check, Plus } from 'lucide-react';
import { useState } from 'react';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from '@/components/ui/sheet';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command';
import { Checkbox } from '@/components/ui/checkbox';
import { Separator } from '@/components/ui/separator';
import { TagPicker } from '@/components/shared/tag-picker';
import { ReminderDaysInput } from '@/components/shared/reminder-days-input';
import { YachtForm } from '@/components/yachts/yacht-form';
import { YachtPicker } from '@/components/yachts/yacht-picker';
import { apiFetch } from '@/lib/api/client';
import { useEntityOptions } from '@/hooks/use-entity-options';
import { createInterestSchema, type CreateInterestInput } from '@/lib/validators/interests';
import { PIPELINE_STAGES, STAGE_LABELS, LEAD_CATEGORIES, SOURCES } from '@/lib/constants';
import { cn } from '@/lib/utils';

const CATEGORY_LABELS: Record<string, string> = {
  general_interest: 'General Interest',
  specific_qualified: 'Specific Qualified',
  hot_lead: 'Hot Lead',
};

interface InterestFormProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /**
   * Pre-fill clientId when launching the form from a client detail page.
   * Ignored when `interest` is provided (edit mode).
   */
  defaultClientId?: string;
  interest?: {
    id: string;
    clientId: string;
    clientName?: string | null;
    yachtId?: string | null;
    berthId?: string | null;
    berthMooringNumber?: string | null;
    pipelineStage: string;
    leadCategory?: string | null;
    source?: string | null;
    reminderEnabled?: boolean;
    reminderDays?: number | null;
    tags?: Array<{ id: string }>;
    desiredLengthFt?: string | number | null;
    desiredWidthFt?: string | number | null;
    desiredDraftFt?: string | number | null;
  };
}

export function InterestForm({ open, onOpenChange, defaultClientId, interest }: InterestFormProps) {
  const queryClient = useQueryClient();
  const isEdit = !!interest;

  const [clientOpen, setClientOpen] = useState(false);
  const [berthOpen, setBerthOpen] = useState(false);
  const [desiredUnit, setDesiredUnit] = useState<'ft' | 'm'>('ft');

  const {
    handleSubmit,
    watch,
    setValue,
    reset,
    formState: { errors, isSubmitting, isDirty },
  } = useForm<CreateInterestInput>({
    resolver: zodResolver(createInterestSchema),
    defaultValues: {
      clientId: '',
      yachtId: undefined,
      pipelineStage: 'open',
      reminderEnabled: false,
      tagIds: [],
    },
  });

  const tagIds = watch('tagIds') ?? [];
  const reminderEnabled = watch('reminderEnabled');
  const selectedClientId = watch('clientId');
  const selectedBerthId = watch('berthId');
  const selectedYachtId = watch('yachtId');
  const [createYachtOpen, setCreateYachtOpen] = useState(false);
  const [discardConfirmOpen, setDiscardConfirmOpen] = useState(false);

  function requestClose() {
    if (isDirty && !isSubmitting && !mutation.isPending) {
      setDiscardConfirmOpen(true);
      return;
    }
    onOpenChange(false);
  }

  // Fetch the selected client's company memberships so the YachtPicker can
  // include yachts owned by companies the client belongs to (e.g. a
  // managing-director client whose yachts are titled to the company).
  const { data: clientDetail } = useQuery<{
    data: { companies?: Array<{ company: { id: string } }> };
  }>({
    queryKey: ['client-detail-for-interest-form', selectedClientId],
    queryFn: () => apiFetch(`/api/v1/clients/${selectedClientId}`),
    enabled: !!selectedClientId,
  });
  const memberCompanyIds: string[] = clientDetail?.data.companies?.map((m) => m.company.id) ?? [];
  const yachtOwnerFilter = selectedClientId
    ? [
        { type: 'client' as const, id: selectedClientId },
        ...memberCompanyIds.map((id) => ({ type: 'company' as const, id })),
      ]
    : undefined;

  const {
    options: clientOptions,
    isLoading: clientsLoading,
    setSearch: setClientSearch,
  } = useEntityOptions({
    endpoint: '/api/v1/clients/options',
    labelKey: 'fullName',
  });

  const {
    options: berthOptions,
    isLoading: berthsLoading,
    setSearch: setBerthSearch,
  } = useEntityOptions({
    endpoint: '/api/v1/berths/options',
    labelKey: 'mooringNumber',
  });

  useEffect(() => {
    if (interest && open) {
      reset({
        clientId: interest.clientId,
        yachtId: interest.yachtId ?? undefined,
        berthId: interest.berthId ?? undefined,
        pipelineStage: interest.pipelineStage as (typeof PIPELINE_STAGES)[number],
        leadCategory: interest.leadCategory as (typeof LEAD_CATEGORIES)[number] | undefined,
        source: interest.source ?? undefined,
        reminderEnabled: interest.reminderEnabled ?? false,
        reminderDays: interest.reminderDays ?? undefined,
        tagIds: interest.tags?.map((t) => t.id) ?? [],
        desiredLengthFt:
          interest.desiredLengthFt === null || interest.desiredLengthFt === undefined
            ? undefined
            : String(interest.desiredLengthFt),
        desiredWidthFt:
          interest.desiredWidthFt === null || interest.desiredWidthFt === undefined
            ? undefined
            : String(interest.desiredWidthFt),
        desiredDraftFt:
          interest.desiredDraftFt === null || interest.desiredDraftFt === undefined
            ? undefined
            : String(interest.desiredDraftFt),
      });
    } else if (!interest && open) {
      reset({
        clientId: defaultClientId ?? '',
        yachtId: undefined,
        pipelineStage: 'open',
        reminderEnabled: false,
        tagIds: [],
      });
    }
  }, [interest, defaultClientId, open, reset]);

  const mutation = useMutation({
    mutationFn: async (data: CreateInterestInput) => {
      if (isEdit) {
        const { tagIds: tIds, ...rest } = data;
        await apiFetch(`/api/v1/interests/${interest!.id}`, { method: 'PATCH', body: rest });
        if (tIds) {
          await apiFetch(`/api/v1/interests/${interest!.id}/tags`, {
            method: 'PUT',
            body: { tagIds: tIds },
          });
        }
      } else {
        await apiFetch('/api/v1/interests', { method: 'POST', body: data });
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['interests'] });
      onOpenChange(false);
    },
  });

  const selectedClient = clientOptions.find((c) => c.value === selectedClientId);
  const selectedBerth = berthOptions.find((b) => b.value === selectedBerthId);

  return (
    <Sheet
      open={open}
      onOpenChange={(next) => {
        if (next) {
          onOpenChange(true);
          return;
        }
        requestClose();
      }}
    >
      <SheetContent className="w-full sm:max-w-2xl overflow-y-auto">
        <SheetHeader>
          <SheetTitle>{isEdit ? 'Edit Interest' : 'New Interest'}</SheetTitle>
        </SheetHeader>

        <form onSubmit={handleSubmit((data) => mutation.mutate(data))} className="space-y-6 py-6">
          {/* Client */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Client & Berth
            </h3>

            <div className="space-y-1">
              <Label>Client *</Label>
              <Popover open={clientOpen} onOpenChange={setClientOpen} modal>
                <PopoverTrigger asChild>
                  <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={clientOpen}
                    className={cn(
                      'w-full justify-between',
                      !selectedClientId && 'text-muted-foreground',
                    )}
                    disabled={isEdit}
                  >
                    {selectedClient?.label ?? interest?.clientName ?? 'Select client...'}
                    <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-[var(--radix-popper-anchor-width)] min-w-[280px] p-0">
                  {/* shouldFilter={false}: server-side search via setClientSearch
                      drives the result set. Without this, cmdk's default filter
                      matches the user's typed text against CommandItem.value
                      (the client UUID) and silently drops every result that
                      doesn't contain the typed substring in its id. */}
                  <Command shouldFilter={false}>
                    <CommandInput placeholder="Search clients..." onValueChange={setClientSearch} />
                    <CommandList>
                      <CommandEmpty>
                        {clientsLoading ? 'Loading...' : 'No clients found.'}
                      </CommandEmpty>
                      <CommandGroup>
                        {clientOptions.map((option) => (
                          <CommandItem
                            key={option.value}
                            value={option.value}
                            onSelect={(val) => {
                              setValue('clientId', val);
                              setClientOpen(false);
                            }}
                          >
                            <Check
                              className={cn(
                                'mr-2 h-4 w-4',
                                selectedClientId === option.value ? 'opacity-100' : 'opacity-0',
                              )}
                            />
                            {option.label}
                          </CommandItem>
                        ))}
                      </CommandGroup>
                    </CommandList>
                  </Command>
                </PopoverContent>
              </Popover>
              {errors.clientId && (
                <p className="text-xs text-destructive">{errors.clientId.message}</p>
              )}
            </div>

            <div className="space-y-1">
              <Label>Berth (optional)</Label>
              <Popover open={berthOpen} onOpenChange={setBerthOpen} modal>
                <PopoverTrigger asChild>
                  <Button
                    variant="outline"
                    role="combobox"
                    aria-expanded={berthOpen}
                    className={cn(
                      'w-full justify-between',
                      !selectedBerthId && 'text-muted-foreground',
                    )}
                  >
                    {selectedBerth?.label ?? interest?.berthMooringNumber ?? 'Select berth...'}
                    <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-[var(--radix-popper-anchor-width)] min-w-[280px] p-0">
                  <Command shouldFilter={false}>
                    <CommandInput placeholder="Search berths..." onValueChange={setBerthSearch} />
                    <CommandList>
                      <CommandEmpty>
                        {berthsLoading ? 'Loading...' : 'No berths found.'}
                      </CommandEmpty>
                      <CommandGroup>
                        <CommandItem
                          value=""
                          onSelect={() => {
                            setValue('berthId', undefined);
                            setBerthOpen(false);
                          }}
                        >
                          <Check
                            className={cn(
                              'mr-2 h-4 w-4',
                              !selectedBerthId ? 'opacity-100' : 'opacity-0',
                            )}
                          />
                          None
                        </CommandItem>
                        {berthOptions.map((option) => (
                          <CommandItem
                            key={option.value}
                            value={option.value}
                            onSelect={(val) => {
                              setValue('berthId', val);
                              setBerthOpen(false);
                            }}
                          >
                            <Check
                              className={cn(
                                'mr-2 h-4 w-4',
                                selectedBerthId === option.value ? 'opacity-100' : 'opacity-0',
                              )}
                            />
                            {option.label}
                          </CommandItem>
                        ))}
                      </CommandGroup>
                    </CommandList>
                  </Command>
                </PopoverContent>
              </Popover>
            </div>

            <div className="space-y-2">
              <div className="flex items-center justify-between">
                <Label>Yacht</Label>
                {selectedClientId && (
                  <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    className="h-7 text-xs"
                    onClick={() => setCreateYachtOpen(true)}
                  >
                    <Plus className="mr-1 h-3 w-3" />
                    Add new
                  </Button>
                )}
              </div>
              <YachtPicker
                value={selectedYachtId ?? null}
                onChange={(id) => setValue('yachtId', id ?? undefined)}
                ownerFilter={yachtOwnerFilter}
                disabled={!selectedClientId}
                placeholder={selectedClientId ? 'Select yacht...' : 'Select a client first'}
              />
              <p className="text-xs text-muted-foreground">
                Required before the interest can leave the &quot;Open&quot; stage.
                {memberCompanyIds.length > 0 && (
                  <>
                    {' '}
                    Includes yachts from {memberCompanyIds.length}{' '}
                    {memberCompanyIds.length === 1 ? 'member company' : 'member companies'}.
                  </>
                )}
              </p>
            </div>
          </div>

          <Separator />

          {/* Pipeline */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Pipeline
            </h3>
            <div className="grid grid-cols-2 gap-4">
              <div className="space-y-1">
                <Label>Stage</Label>
                <Select
                  value={watch('pipelineStage') ?? 'open'}
                  onValueChange={(v) =>
                    setValue('pipelineStage', v as (typeof PIPELINE_STAGES)[number])
                  }
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select stage" />
                  </SelectTrigger>
                  <SelectContent>
                    {PIPELINE_STAGES.map((s) => (
                      <SelectItem key={s} value={s}>
                        {STAGE_LABELS[s]}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="space-y-1">
                <Label>Lead Category</Label>
                <Select
                  value={watch('leadCategory') ?? ''}
                  onValueChange={(v) =>
                    setValue(
                      'leadCategory',
                      v ? (v as (typeof LEAD_CATEGORIES)[number]) : undefined,
                    )
                  }
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select category" />
                  </SelectTrigger>
                  <SelectContent>
                    {LEAD_CATEGORIES.map((c) => (
                      <SelectItem key={c} value={c}>
                        {CATEGORY_LABELS[c] ?? c}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="space-y-1">
                <Label>Source</Label>
                <Select
                  value={watch('source') ?? ''}
                  onValueChange={(v) => setValue('source', v || undefined)}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select source" />
                  </SelectTrigger>
                  <SelectContent>
                    {SOURCES.map((s) => (
                      <SelectItem key={s.value} value={s.value}>
                        {s.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            </div>
          </div>

          <Separator />

          {/* Desired berth dimensions (recommender inputs) */}
          <div className="space-y-3">
            <div className="flex items-start justify-between gap-3">
              <div>
                <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
                  Berth size desired
                </h3>
                <p className="mt-1 text-xs text-muted-foreground">
                  Optional - the recommender treats blank fields as no constraint on that axis.
                </p>
              </div>
              <UnitToggle value={desiredUnit} onChange={setDesiredUnit} />
            </div>
            <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
              <DimensionInput
                htmlId="desiredLengthFt"
                label="Length"
                placeholder={desiredUnit === 'ft' ? 'e.g. 60' : 'e.g. 18.29'}
                unit={desiredUnit}
                ftValue={watch('desiredLengthFt') as string | undefined}
                onChangeFt={(v) => setValue('desiredLengthFt', v, { shouldDirty: true })}
              />
              <DimensionInput
                htmlId="desiredWidthFt"
                label="Width"
                placeholder={desiredUnit === 'ft' ? 'e.g. 18' : 'e.g. 5.49'}
                unit={desiredUnit}
                ftValue={watch('desiredWidthFt') as string | undefined}
                onChangeFt={(v) => setValue('desiredWidthFt', v, { shouldDirty: true })}
              />
              <DimensionInput
                htmlId="desiredDraftFt"
                label="Draft"
                placeholder={desiredUnit === 'ft' ? 'e.g. 6' : 'e.g. 1.83'}
                unit={desiredUnit}
                ftValue={watch('desiredDraftFt') as string | undefined}
                onChangeFt={(v) => setValue('desiredDraftFt', v, { shouldDirty: true })}
              />
            </div>
          </div>

          <Separator />

          {/* Reminder */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Reminder
            </h3>
            <div className="flex items-center gap-2">
              <Checkbox
                id="reminderEnabled"
                checked={reminderEnabled ?? false}
                onCheckedChange={(v) => setValue('reminderEnabled', !!v)}
              />
              <Label htmlFor="reminderEnabled">Enable reminder</Label>
            </div>
            {reminderEnabled && (
              <div className="space-y-1">
                <Label htmlFor="reminderDays">Reminder cadence</Label>
                <ReminderDaysInput
                  id="reminderDays"
                  value={watch('reminderDays') ?? null}
                  onChange={(v) => setValue('reminderDays', v ?? undefined)}
                />
              </div>
            )}
          </div>

          <Separator />

          {/* Tags */}
          <div className="space-y-2">
            <Label>Tags</Label>
            <TagPicker selectedIds={tagIds} onChange={(ids) => setValue('tagIds', ids)} />
          </div>

          <SheetFooter>
            <Button type="button" variant="outline" onClick={requestClose}>
              Cancel
            </Button>
            <Button type="submit" disabled={isSubmitting || mutation.isPending}>
              {(isSubmitting || mutation.isPending) && (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              )}
              {isEdit ? 'Save Changes' : 'Create Interest'}
            </Button>
          </SheetFooter>
        </form>

        <AlertDialog open={discardConfirmOpen} onOpenChange={setDiscardConfirmOpen}>
          <AlertDialogContent>
            <AlertDialogHeader>
              <AlertDialogTitle>Discard unsaved changes?</AlertDialogTitle>
              <AlertDialogDescription>
                You&apos;ve filled in some fields. Closing now will lose them.
              </AlertDialogDescription>
            </AlertDialogHeader>
            <AlertDialogFooter>
              <AlertDialogCancel>Keep editing</AlertDialogCancel>
              <AlertDialogAction
                onClick={() => {
                  setDiscardConfirmOpen(false);
                  onOpenChange(false);
                }}
                className="bg-destructive text-destructive-foreground hover:bg-destructive/90 focus:ring-destructive"
              >
                Discard
              </AlertDialogAction>
            </AlertDialogFooter>
          </AlertDialogContent>
        </AlertDialog>
      </SheetContent>
      {createYachtOpen && selectedClientId && (
        <YachtForm
          open={createYachtOpen}
          onOpenChange={setCreateYachtOpen}
          initialOwner={{ type: 'client', id: selectedClientId }}
        />
      )}
    </Sheet>
  );
}

// ── Helpers for the "Berth size desired" section ──────────────────────────────

const FT_PER_M = 1 / 0.3048;

function round2(n: number): number {
  return Math.round(n * 100) / 100;
}

function UnitToggle({ value, onChange }: { value: 'ft' | 'm'; onChange: (v: 'ft' | 'm') => void }) {
  return (
    <div
      className="inline-flex rounded-md border bg-muted/30 p-0.5 text-xs"
      role="radiogroup"
      aria-label="Display unit"
    >
      {(['ft', 'm'] as const).map((u) => (
        <button
          key={u}
          type="button"
          role="radio"
          aria-checked={value === u}
          onClick={() => onChange(u)}
          className={cn(
            'h-7 rounded px-3 font-medium transition-colors',
            value === u
              ? 'bg-background text-foreground shadow-sm'
              : 'text-muted-foreground hover:text-foreground',
          )}
        >
          {u}
        </button>
      ))}
    </div>
  );
}

interface DimensionInputProps {
  htmlId: string;
  label: string;
  placeholder?: string;
  unit: 'ft' | 'm';
  ftValue: string | number | undefined;
  onChangeFt: (next: string | undefined) => void;
}

/**
 * Single dimension input bound to a form value stored in feet. Renders the
 * value in the rep's chosen display unit and converts back on edit. The form
 * state stays canonical ft so the recommender (which queries `b.length_ft`
 * etc.) sees the same number regardless of which unit the rep typed in.
 *
 * Local `display` state preserves mid-typing strings like "18." that would
 * otherwise be lost to round-tripping through Number().
 */
function DimensionInput({
  htmlId,
  label,
  placeholder,
  unit,
  ftValue,
  onChangeFt,
}: DimensionInputProps) {
  const focusedRef = useRef(false);
  const [display, setDisplay] = useState<string>(() => computeDisplay(ftValue, unit));

  // Re-sync from the canonical ft value when it changes externally (form
  // reset, unit toggle). Skip while focused so we don't fight keystrokes.
  useEffect(() => {
    if (focusedRef.current) return;
    setDisplay(computeDisplay(ftValue, unit));
  }, [ftValue, unit]);

  const altValue = computeAltDisplay(ftValue, unit);

  return (
    <div className="space-y-1">
      <Label htmlFor={htmlId}>
        {label} <span className="text-muted-foreground">({unit})</span>
      </Label>
      <Input
        id={htmlId}
        type="number"
        inputMode="decimal"
        step="0.01"
        min={0}
        placeholder={placeholder}
        value={display}
        onFocus={() => {
          focusedRef.current = true;
        }}
        onBlur={() => {
          focusedRef.current = false;
          // Canonicalize the display from the ft source-of-truth on blur so
          // any mid-typed garbage clears.
          setDisplay(computeDisplay(ftValue, unit));
        }}
        onChange={(e) => {
          const raw = e.target.value;
          setDisplay(raw);
          if (raw === '') {
            onChangeFt(undefined);
            return;
          }
          const n = parseFloat(raw);
          if (!Number.isFinite(n) || n <= 0) {
            onChangeFt(undefined);
            return;
          }
          const ft = unit === 'ft' ? n : n * FT_PER_M;
          onChangeFt(String(round2(ft)));
        }}
      />
      {altValue ? (
        <p className="text-[11px] leading-tight text-muted-foreground">≈ {altValue}</p>
      ) : null}
    </div>
  );
}

function computeDisplay(ftValue: string | number | undefined, unit: 'ft' | 'm'): string {
  if (ftValue === undefined || ftValue === null || ftValue === '') return '';
  const ft = typeof ftValue === 'number' ? ftValue : Number(ftValue);
  if (!Number.isFinite(ft)) return '';
  const v = unit === 'ft' ? ft : ft * 0.3048;
  return String(round2(v));
}

function computeAltDisplay(
  ftValue: string | number | undefined,
  unit: 'ft' | 'm',
): string | null {
  if (ftValue === undefined || ftValue === null || ftValue === '') return null;
  const ft = typeof ftValue === 'number' ? ftValue : Number(ftValue);
  if (!Number.isFinite(ft) || ft <= 0) return null;
  return unit === 'ft' ? `${round2(ft * 0.3048)} m` : `${round2(ft)} ft`;
}
