'use client';

import { useEffect } from 'react';
import { useForm, useFieldArray } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { Plus, Trash2, Loader2 } from 'lucide-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 { Checkbox } from '@/components/ui/checkbox';
import { Separator } from '@/components/ui/separator';
import { TagPicker } from '@/components/shared/tag-picker';
import { CountryCombobox } from '@/components/shared/country-combobox';
import { TimezoneCombobox } from '@/components/shared/timezone-combobox';
import { PhoneInput } from '@/components/shared/phone-input';
import { DedupSuggestionPanel } from '@/components/clients/dedup-suggestion-panel';
import { apiFetch } from '@/lib/api/client';
import type { z } from 'zod';
import { createClientSchema, type CreateClientInput } from '@/lib/validators/clients';
import { SOURCES } from '@/lib/constants';
import type { CountryCode } from '@/lib/i18n/countries';
import { primaryTimezoneFor } from '@/lib/i18n/timezones';

interface ClientFormProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** Optional callback fired when the dedup suggestion panel reports
   *  the user picked an existing client. The form closes; parent is
   *  responsible for navigating to the existing client's detail page
   *  or opening the create-interest dialog pre-filled with that
   *  clientId. Skipped in edit mode. */
  onUseExistingClient?: (clientId: string) => void;
  /** If provided, form is in edit mode */
  client?: {
    id: string;
    fullName: string;
    nationalityIso?: string | null;
    preferredContactMethod?: string | null;
    preferredLanguage?: string | null;
    timezone?: string | null;
    source?: string | null;
    sourceDetails?: string | null;
    contacts?: Array<{
      channel: string;
      value: string;
      valueE164?: string | null;
      valueCountry?: string | null;
      label?: string | null;
      isPrimary?: boolean;
      notes?: string | null;
    }>;
    tags?: Array<{ id: string }>;
  };
}

export function ClientForm({ open, onOpenChange, client, onUseExistingClient }: ClientFormProps) {
  const queryClient = useQueryClient();
  const isEdit = !!client;

  const {
    register,
    handleSubmit,
    control,
    watch,
    setValue,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<z.input<typeof createClientSchema>, unknown, CreateClientInput>({
    resolver: zodResolver(createClientSchema),
    defaultValues: {
      fullName: '',
      contacts: [{ channel: 'email', value: '', isPrimary: true }],
      tagIds: [],
    },
  });

  const { fields, append, remove } = useFieldArray({ control, name: 'contacts' });
  const tagIds = watch('tagIds') ?? [];

  // When the rep picks a country and no timezone is set yet, pre-fill the
  // timezone with the country's primary IANA zone. Skips when the user has
  // already chosen a zone explicitly so we never clobber a deliberate pick.
  const watchedNationality = watch('nationalityIso');
  const watchedTimezone = watch('timezone');
  useEffect(() => {
    if (!watchedNationality || watchedTimezone) return;
    const primary = primaryTimezoneFor(watchedNationality as CountryCode);
    if (primary) setValue('timezone', primary);
  }, [watchedNationality, watchedTimezone, setValue]);

  // Populate form when editing
  useEffect(() => {
    if (client && open) {
      reset({
        fullName: client.fullName,
        nationalityIso: client.nationalityIso ?? undefined,
        preferredContactMethod:
          (client.preferredContactMethod as CreateClientInput['preferredContactMethod']) ??
          undefined,
        preferredLanguage: client.preferredLanguage ?? undefined,
        timezone: client.timezone ?? undefined,
        source: (client.source as CreateClientInput['source']) ?? undefined,
        sourceDetails: client.sourceDetails ?? undefined,
        contacts:
          client.contacts && client.contacts.length > 0
            ? client.contacts.map((c) => ({
                channel: c.channel as 'email' | 'phone' | 'whatsapp' | 'other',
                value: c.value,
                valueE164: c.valueE164 ?? undefined,
                valueCountry: c.valueCountry ?? undefined,
                label: c.label ?? undefined,
                isPrimary: c.isPrimary ?? false,
                notes: c.notes ?? undefined,
              }))
            : [{ channel: 'email', value: '', isPrimary: true }],
        tagIds: client.tags?.map((t) => t.id) ?? [],
      });
    } else if (!client && open) {
      reset({
        fullName: '',
        contacts: [{ channel: 'email', value: '', isPrimary: true }],
        tagIds: [],
      });
    }
  }, [client, open, reset]);

  const mutation = useMutation({
    mutationFn: async (data: CreateClientInput) => {
      if (isEdit) {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        const { contacts, tagIds: tIds, ...rest } = data;
        await apiFetch(`/api/v1/clients/${client!.id}`, { method: 'PATCH', body: rest });
        if (tIds) {
          await apiFetch(`/api/v1/clients/${client!.id}/tags`, {
            method: 'PUT',
            body: { tagIds: tIds },
          });
        }
      } else {
        await apiFetch('/api/v1/clients', { method: 'POST', body: data });
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['clients'] });
      onOpenChange(false);
    },
  });

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

        <form onSubmit={handleSubmit((data) => mutation.mutate(data))} className="space-y-6 py-6">
          {/* Dedup suggestion - only on the create path. Watches the
              live form values for email / phone / name and surfaces
              an existing client when one matches. The user can
              attach the new interest to that client instead of
              creating a duplicate. */}
          {!isEdit ? (
            <DedupSuggestionPanel
              email={watch('contacts')?.find((c) => c?.channel === 'email')?.value ?? null}
              phone={
                watch('contacts')?.find((c) => c?.channel === 'phone' || c?.channel === 'whatsapp')
                  ?.valueE164 ?? null
              }
              name={watch('fullName') ?? null}
              onUseExisting={(match) => {
                onUseExistingClient?.(match.clientId);
                onOpenChange(false);
              }}
            />
          ) : null}

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

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

              <div className="space-y-1">
                <Label>Country</Label>
                <CountryCombobox
                  value={watch('nationalityIso')}
                  onChange={(iso) => setValue('nationalityIso', iso ?? undefined)}
                  data-testid="client-nationality"
                />
              </div>
            </div>
          </div>

          <Separator />

          {/* Contacts */}
          <div className="space-y-4">
            <div className="flex items-center justify-between">
              <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
                Contacts
              </h3>
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => append({ channel: 'email', value: '', isPrimary: false })}
              >
                <Plus className="mr-1 h-3.5 w-3.5" />
                Add Contact
              </Button>
            </div>

            {errors.contacts?.root && (
              <p className="text-xs text-destructive">{errors.contacts.root.message}</p>
            )}

            <div className="space-y-3">
              {fields.map((field, index) => (
                <div key={field.id} className="space-y-3 p-3 rounded-lg border bg-muted/30">
                  <div className="grid grid-cols-1 gap-3 sm:grid-cols-12 sm:items-end sm:gap-2">
                    <div className="space-y-1 sm:col-span-3">
                      <Label className="text-xs">Channel</Label>
                      <Select
                        value={watch(`contacts.${index}.channel`)}
                        onValueChange={(v) =>
                          setValue(
                            `contacts.${index}.channel`,
                            v as 'email' | 'phone' | 'whatsapp' | 'other',
                          )
                        }
                      >
                        <SelectTrigger className="h-9 sm:h-8">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="email">Email</SelectItem>
                          <SelectItem value="phone">Phone</SelectItem>
                          <SelectItem value="whatsapp">WhatsApp</SelectItem>
                          <SelectItem value="other">Other</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>

                    <div className="space-y-1 sm:col-span-5">
                      <Label className="text-xs">Value</Label>
                      {(() => {
                        const channel = watch(`contacts.${index}.channel`);
                        if (channel === 'phone' || channel === 'whatsapp') {
                          const e164 = watch(`contacts.${index}.valueE164`) ?? null;
                          const country =
                            (watch(`contacts.${index}.valueCountry`) as CountryCode | undefined) ??
                            undefined;
                          return (
                            <PhoneInput
                              value={
                                e164 || country
                                  ? {
                                      e164: e164 ?? null,
                                      country: country ?? 'US',
                                    }
                                  : null
                              }
                              onChange={(v) => {
                                setValue(`contacts.${index}.value`, v.e164 ?? '');
                                setValue(`contacts.${index}.valueE164`, v.e164 ?? undefined);
                                setValue(`contacts.${index}.valueCountry`, v.country);
                              }}
                              data-testid={`contact-${index}-phone`}
                            />
                          );
                        }
                        return (
                          <Input
                            {...register(`contacts.${index}.value`)}
                            className="h-9 sm:h-8"
                            placeholder={channel === 'email' ? 'email@example.com' : 'value'}
                          />
                        );
                      })()}
                    </div>

                    <div className="space-y-1 sm:col-span-4">
                      <Label className="text-xs">
                        {watch(`contacts.${index}.channel`) === 'other' ? 'Specify' : 'Label'}
                      </Label>
                      <Input
                        {...register(`contacts.${index}.label`)}
                        className="h-9 sm:h-8"
                        placeholder={
                          watch(`contacts.${index}.channel`) === 'other'
                            ? 'e.g. Telegram, Signal'
                            : 'work'
                        }
                      />
                    </div>
                  </div>

                  {/* Bottom strip: Primary toggle left, delete right. Sits on
                      its own row on every breakpoint so neither control gets
                      squashed by the field columns above. */}
                  <div className="flex items-center justify-between gap-3">
                    <label className="flex items-center gap-2 text-sm cursor-pointer select-none">
                      <Checkbox
                        checked={watch(`contacts.${index}.isPrimary`)}
                        onCheckedChange={(v) => setValue(`contacts.${index}.isPrimary`, !!v)}
                      />
                      <span className="font-medium">Primary contact</span>
                    </label>
                    {fields.length > 1 && (
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        className="h-8 text-destructive hover:text-destructive"
                        onClick={() => remove(index)}
                      >
                        <Trash2 className="mr-1 h-3.5 w-3.5" />
                        Remove
                      </Button>
                    )}
                  </div>
                </div>
              ))}
            </div>
          </div>

          <Separator />

          {/* Source & Preferences */}
          <div className="space-y-4">
            <h3 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
              Source & Preferences
            </h3>
            <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
              <div className="space-y-1">
                <Label>Source</Label>
                <Select
                  value={watch('source') ?? ''}
                  onValueChange={(v) =>
                    setValue('source', v as 'website' | 'manual' | 'referral' | 'broker' | 'other')
                  }
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select source" />
                  </SelectTrigger>
                  <SelectContent>
                    {SOURCES.map((s) => (
                      <SelectItem key={s.value} value={s.value}>
                        {s.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
              <div className="space-y-1">
                <Label>Preferred Contact Method</Label>
                <Select
                  value={watch('preferredContactMethod') ?? ''}
                  onValueChange={(v) =>
                    setValue('preferredContactMethod', v as 'email' | 'phone' | 'whatsapp')
                  }
                >
                  <SelectTrigger>
                    <SelectValue placeholder="Select method" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="email">Email</SelectItem>
                    <SelectItem value="phone">Phone</SelectItem>
                    <SelectItem value="whatsapp">WhatsApp</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div className="space-y-1">
                <Label>Timezone</Label>
                <TimezoneCombobox
                  value={watch('timezone')}
                  onChange={(tz) => setValue('timezone', tz ?? undefined)}
                  countryHint={(watch('nationalityIso') as CountryCode | undefined) ?? undefined}
                  data-testid="client-timezone"
                />
              </div>
              <div className="sm:col-span-2 space-y-1">
                <Label>Source Details</Label>
                <Input {...register('sourceDetails')} placeholder="Referred by John Doe" />
              </div>
            </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={() => onOpenChange(false)}>
              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 Client'}
            </Button>
          </SheetFooter>
        </form>
      </SheetContent>
    </Sheet>
  );
}
