'use client';

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

import { Button } from '@/components/ui/button';
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 { Separator } from '@/components/ui/separator';
import { CountryCombobox } from '@/components/shared/country-combobox';
import { OwnerPicker, type OwnerRef } from '@/components/shared/owner-picker';
import { TagPicker } from '@/components/shared/tag-picker';
import { apiFetch } from '@/lib/api/client';
import { useFormScrollToError } from '@/hooks/use-form-scroll-to-error';
import { FormErrorSummary } from '@/components/forms/form-error-summary';
import { feetToMeters, metersToFeet } from '@/components/yachts/yacht-dimensions';
import type { z } from 'zod';
import { createYachtSchema, type CreateYachtInput } from '@/lib/validators/yachts';

interface YachtFormProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** If provided, form is in edit mode */
  yacht?: {
    id: string;
    name: string;
    hullNumber?: string | null;
    registration?: string | null;
    flag?: string | null;
    yearBuilt?: number | null;
    builder?: string | null;
    model?: string | null;
    hullMaterial?: string | null;
    lengthFt?: string | null;
    widthFt?: string | null;
    draftFt?: string | null;
    lengthM?: string | null;
    widthM?: string | null;
    draftM?: string | null;
    currentOwnerType: 'client' | 'company';
    currentOwnerId: string;
    status?: string | null;
    notes?: string | null;
  };
  /**
   * In create mode, pre-select the owner so a user opening this form from
   * a client/company detail page doesn't have to manually re-pick the
   * entity they're already on. Ignored in edit mode (the existing
   * owner-history workflow is the right surface for ownership changes).
   */
  initialOwner?: { type: 'client' | 'company'; id: string };
  /**
   * Phase 3c - extra fields baked into the create POST. Lets the EOI
   * spawn flow stamp the new yacht with `source='eoi-generated'` (and
   * optionally `sourceDocumentId` when the calling document is already
   * persisted) without exposing those fields in the form UI.
   */
  createExtras?: Partial<{
    source: 'manual' | 'imported' | 'eoi-generated';
    sourceDocumentId: string;
  }>;
  /**
   * Phase 3c - called with the new yacht's id/name after a successful
   * create POST, BEFORE the dialog closes. The EOI spawn flow uses this
   * to PATCH the interest's yachtId so the EOI re-fetches with the
   * just-spawned yacht in scope.
   */
  onCreated?: (yacht: { id: string; name: string }) => void | Promise<void>;
  /**
   * Optional initial values for the create flow - used by the global
   * command-search quick-create ("New yacht 'matthew'" → lands on
   * `/yachts?create=1&prefill_name=matthew`). Ignored in edit mode.
   */
  prefill?: {
    name?: string;
  };
}

type YachtStatus = 'active' | 'retired' | 'sold_away';

export function YachtForm({
  open,
  onOpenChange,
  yacht,
  initialOwner,
  createExtras,
  onCreated,
  prefill,
}: YachtFormProps) {
  const queryClient = useQueryClient();
  const isEdit = !!yacht;
  const [formError, setFormError] = useState<string | null>(null);

  const {
    register,
    handleSubmit,
    watch,
    setValue,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<z.input<typeof createYachtSchema>, unknown, CreateYachtInput>({
    resolver: zodResolver(createYachtSchema),
    defaultValues: {
      name: '',
      status: 'active',
      tagIds: [],
    },
  });

  const scrollOnError = useFormScrollToError(handleSubmit, errors);

  const tagIds = watch('tagIds') ?? [];
  const owner = watch('owner') as OwnerRef | undefined;
  const status = watch('status') ?? 'active';

  // Populate form when editing, or reset to defaults in create mode.
  useEffect(() => {
    if (yacht && open) {
      reset({
        name: yacht.name,
        hullNumber: yacht.hullNumber ?? undefined,
        registration: yacht.registration ?? undefined,
        flag: yacht.flag ?? undefined,
        yearBuilt: yacht.yearBuilt ?? undefined,
        builder: yacht.builder ?? undefined,
        model: yacht.model ?? undefined,
        hullMaterial: yacht.hullMaterial ?? undefined,
        lengthFt: yacht.lengthFt ?? undefined,
        widthFt: yacht.widthFt ?? undefined,
        draftFt: yacht.draftFt ?? undefined,
        lengthM: yacht.lengthM ?? undefined,
        widthM: yacht.widthM ?? undefined,
        draftM: yacht.draftM ?? undefined,
        // Owner is required by the schema in create mode. In edit mode we
        // strip it before PATCH, but we still satisfy the resolver by
        // supplying the current owner.
        owner: { type: yacht.currentOwnerType, id: yacht.currentOwnerId },
        status: (yacht.status as YachtStatus | null) ?? 'active',
        notes: yacht.notes ?? undefined,
        tagIds: [],
      });
    } else if (!yacht && open) {
      reset({
        name: prefill?.name ?? '',
        status: 'active',
        tagIds: [],
        ...(initialOwner ? { owner: initialOwner } : {}),
      });
    }
    setFormError(null);
  }, [yacht, open, reset, initialOwner, prefill]);

  const mutation = useMutation({
    mutationFn: async (data: CreateYachtInput) => {
      if (isEdit) {
        // updateYachtSchema omits owner + tagIds - strip them from PATCH body.
        const { owner: _owner, tagIds: _tIds, ...rest } = data;
        void _owner;
        void _tIds;
        await apiFetch(`/api/v1/yachts/${yacht!.id}`, {
          method: 'PATCH',
          body: rest,
        });
        return null;
      }
      const created = await apiFetch<{ data: { id: string; name: string } }>('/api/v1/yachts', {
        method: 'POST',
        body: { ...data, ...(createExtras ?? {}) },
      });
      return created.data;
    },
    onSuccess: async (created) => {
      queryClient.invalidateQueries({ queryKey: ['yachts'] });
      if (created && onCreated) {
        await onCreated(created);
      }
      onOpenChange(false);
    },
    onError: (err: Error) => {
      setFormError(err.message || 'Failed to save yacht');
    },
  });

  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      <SheetContent className="w-full sm:max-w-2xl lg:max-w-4xl overflow-y-auto">
        <SheetHeader>
          <SheetTitle>{isEdit ? 'Edit Yacht' : 'New Yacht'}</SheetTitle>
        </SheetHeader>

        <form
          onSubmit={scrollOnError((data) => {
            setFormError(null);
            mutation.mutate(data);
          })}
          className="space-y-6 py-6"
        >
          <FormErrorSummary errors={errors} />
          {/* Basic */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Basic
            </h3>

            <div className="grid grid-cols-2 gap-4">
              <div className="col-span-2 space-y-1">
                <Label>Name *</Label>
                <Input {...register('name')} placeholder="Sea Breeze" />
                {errors.name && <p className="text-xs text-destructive">{errors.name.message}</p>}
              </div>

              <div className="space-y-1">
                <Label>Hull Number</Label>
                <Input {...register('hullNumber')} placeholder="HIN" />
              </div>

              <div className="space-y-1">
                <Label>Registration</Label>
                <Input {...register('registration')} placeholder="Registration #" />
              </div>

              <div className="space-y-1">
                <Label>Flag</Label>
                <CountryCombobox
                  value={watch('flag') ?? null}
                  onChange={(iso) => setValue('flag', iso ?? undefined)}
                  placeholder="Select flag country…"
                  clearable
                />
              </div>

              <div className="space-y-1">
                <Label>Year Built</Label>
                <Input
                  type="number"
                  {...register('yearBuilt', { valueAsNumber: true })}
                  placeholder="2015"
                />
                {errors.yearBuilt && (
                  <p className="text-xs text-destructive">{errors.yearBuilt.message}</p>
                )}
              </div>
            </div>
          </div>

          <Separator />

          {/* Build */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Build
            </h3>
            <div className="grid grid-cols-2 gap-4">
              <div className="space-y-1">
                <Label>Builder</Label>
                <Input {...register('builder')} placeholder="Benetti" />
              </div>
              <div className="space-y-1">
                <Label>Model</Label>
                <Input {...register('model')} placeholder="Classic 120" />
              </div>
              <div className="col-span-2 space-y-1">
                <Label>Hull Material</Label>
                <Input {...register('hullMaterial')} placeholder="Aluminium" />
              </div>
            </div>
          </div>

          <Separator />

          {/* Dimensions  -  auto-convert ft ↔ m. Whichever unit the operator
              types into, the other unit gets recomputed in place. We round
              the converted value to keep the input clean (2 decimal places),
              and skip the recompute when the user is mid-edit on the same
              field so the cursor doesn't jump. */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Dimensions
            </h3>
            <p className="text-xs text-muted-foreground -mt-2">
              Type a value in either ft or m - the other unit auto-fills.
            </p>
            <div className="grid grid-cols-3 gap-4">
              <DimensionPair
                label="Length"
                ftValue={watch('lengthFt')}
                mValue={watch('lengthM')}
                onFtChange={(v) => {
                  setValue('lengthFt', v, { shouldDirty: true });
                  setValue('lengthM', ftToM(v), { shouldDirty: true });
                }}
                onMChange={(v) => {
                  setValue('lengthM', v, { shouldDirty: true });
                  setValue('lengthFt', mToFt(v), { shouldDirty: true });
                }}
                placeholders={{ ft: '120', m: '36.58' }}
              />
              <DimensionPair
                label="Width"
                ftValue={watch('widthFt')}
                mValue={watch('widthM')}
                onFtChange={(v) => {
                  setValue('widthFt', v, { shouldDirty: true });
                  setValue('widthM', ftToM(v), { shouldDirty: true });
                }}
                onMChange={(v) => {
                  setValue('widthM', v, { shouldDirty: true });
                  setValue('widthFt', mToFt(v), { shouldDirty: true });
                }}
                placeholders={{ ft: '25', m: '7.62' }}
              />
              <DimensionPair
                label="Draft"
                ftValue={watch('draftFt')}
                mValue={watch('draftM')}
                onFtChange={(v) => {
                  setValue('draftFt', v, { shouldDirty: true });
                  setValue('draftM', ftToM(v), { shouldDirty: true });
                }}
                onMChange={(v) => {
                  setValue('draftM', v, { shouldDirty: true });
                  setValue('draftFt', mToFt(v), { shouldDirty: true });
                }}
                placeholders={{ ft: '8', m: '2.44' }}
              />
            </div>
          </div>

          <Separator />

          {/* Ownership */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Ownership
            </h3>

            {isEdit ? (
              <p className="rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground">
                Ownership changes use the Transfer button.
              </p>
            ) : (
              <div className="space-y-1">
                <Label>Owner *</Label>
                <OwnerPicker
                  value={owner ?? null}
                  onChange={(v) => {
                    if (v) {
                      setValue('owner', v, { shouldValidate: true });
                    }
                  }}
                />
                {errors.owner && (
                  <p className="text-xs text-destructive">
                    {errors.owner.message ?? 'Owner is required'}
                  </p>
                )}
              </div>
            )}
          </div>

          <Separator />

          {/* Status */}
          <div className="space-y-2">
            <Label>Status</Label>
            <Select value={status} onValueChange={(v) => setValue('status', v as YachtStatus)}>
              <SelectTrigger>
                <SelectValue placeholder="Select status" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="active">Active</SelectItem>
                <SelectItem value="retired">Retired</SelectItem>
                <SelectItem value="sold_away">Sold away</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <Separator />

          {/* Notes */}
          <div className="space-y-2">
            <Label>Notes</Label>
            <Textarea
              {...register('notes')}
              placeholder="Internal notes about this yacht"
              rows={4}
            />
          </div>

          <Separator />

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

          {formError && (
            <p className="text-sm text-destructive" role="alert">
              {formError}
            </p>
          )}

          <SheetFooter>
            <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
              Cancel
            </Button>
            <Button type="submit" disabled={isSubmitting || mutation.isPending}>
              {(isSubmitting || mutation.isPending) && (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" aria-hidden />
              )}
              {isEdit ? 'Save changes' : 'Create Yacht'}
            </Button>
          </SheetFooter>
        </form>
      </SheetContent>
    </Sheet>
  );
}

// Cross-fill the sibling unit. Delegates the math to `yacht-dimensions.ts`
// so the form and the read-side `formatYachtDimensionsBothUnits` agree on
// the formula. 4-decimal precision keeps the round-trip lossless within
// display: `1 ft → 0.3048 m → 1.0000 ft` (after trimZero → "1"); the prior
// 2-decimal precision rounded `1 ft → 0.30 m → 0.98 ft` which lost data
// whenever the rep touched both fields on the same yacht.
function trimZero(s: string): string {
  if (!s.includes('.')) return s;
  return s.replace(/\.?0+$/, '');
}

function ftToM(value: string | null | undefined): string {
  if (value == null || value === '') return '';
  const meters = feetToMeters(value);
  if (meters === null) return '';
  return trimZero(meters.toFixed(4));
}

function mToFt(value: string | null | undefined): string {
  if (value == null || value === '') return '';
  const feet = metersToFeet(value);
  if (feet === null) return '';
  return trimZero(feet.toFixed(4));
}

function DimensionPair({
  label,
  ftValue,
  mValue,
  onFtChange,
  onMChange,
  placeholders,
}: {
  label: string;
  ftValue: string | null | undefined;
  mValue: string | null | undefined;
  onFtChange: (value: string) => void;
  onMChange: (value: string) => void;
  placeholders: { ft: string; m: string };
}) {
  return (
    <div className="space-y-1.5">
      <Label className="text-xs font-medium">{label}</Label>
      <div className="grid grid-cols-2 gap-2">
        <div className="space-y-1">
          <span className="text-xs uppercase tracking-wide text-muted-foreground">ft</span>
          <Input
            inputMode="decimal"
            value={ftValue ?? ''}
            onChange={(e) => onFtChange(e.target.value)}
            placeholder={placeholders.ft}
          />
        </div>
        <div className="space-y-1">
          <span className="text-xs uppercase tracking-wide text-muted-foreground">m</span>
          <Input
            inputMode="decimal"
            value={mValue ?? ''}
            onChange={(e) => onMChange(e.target.value)}
            placeholder={placeholders.m}
          />
        </div>
      </div>
    </div>
  );
}
