import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { z } from 'zod';
import { Loader2 } from 'lucide-react';
import { toast } from 'sonner';
import { PartState } from '@vector/shared';
import {
  Button,
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
  Input,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
  Textarea,
} from '@vector/ui';
import { listManufacturers } from '../../lib/api/manufacturers.js';
import { listBins } from '../../lib/api/bins.js';
import { createPart, updatePart } from '../../lib/api/parts.js';
import type { Part } from '../../lib/api/types.js';
import { ApiRequestError } from '../../lib/api/client.js';
import { queryKeys } from '../../lib/queryKeys.js';
import { partStateOptions } from './PartStateBadge.js';

// Schema reflects the server's CreatePartRequest but keeps strings for the form, letting the
// submit handler coerce to the network shape.
const PartFormSchema = z.object({
  serialNumber: z.string().min(1, 'Required').max(128),
  mpn: z.string().min(1, 'Required').max(128),
  manufacturerId: z.string().uuid('Select a manufacturer'),
  state: PartState,
  binId: z.string().optional(), // '' = none
  price: z.string().optional(), // empty string = null
  notes: z.string().max(4096).optional(),
});
type PartFormValues = z.infer<typeof PartFormSchema>;

const UNASSIGNED = '__none__';

interface PartFormDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  part?: Part | null;
}

export function PartFormDialog({ open, onOpenChange, part }: PartFormDialogProps) {
  const editing = Boolean(part);
  const queryClient = useQueryClient();

  const form = useForm<PartFormValues>({
    resolver: zodResolver(PartFormSchema),
    defaultValues: {
      serialNumber: '',
      mpn: '',
      manufacturerId: '',
      state: 'SPARE',
      binId: '',
      price: '',
      notes: '',
    },
  });

  useEffect(() => {
    if (!open) return;
    form.reset(
      part
        ? {
            serialNumber: part.serialNumber,
            mpn: part.partModel.mpn,
            manufacturerId: part.manufacturerId,
            state: part.state,
            binId: part.binId ?? '',
            price: part.price != null ? String(part.price) : '',
            notes: part.notes ?? '',
          }
        : {
            serialNumber: '',
            mpn: '',
            manufacturerId: '',
            state: 'SPARE',
            binId: '',
            price: '',
            notes: '',
          },
    );
  }, [open, part, form]);

  const manufacturers = useQuery({
    queryKey: queryKeys.manufacturers.list({ pageSize: 100 }),
    queryFn: () => listManufacturers({ pageSize: 100 }),
    enabled: open,
  });

  const bins = useQuery({
    queryKey: queryKeys.bins.list({ pageSize: 100 }),
    queryFn: () => listBins({ pageSize: 100 }),
    enabled: open,
  });

  const mutation = useMutation({
    mutationFn: async (values: PartFormValues) => {
      const payload = {
        serialNumber: values.serialNumber,
        mpn: values.mpn,
        manufacturerId: values.manufacturerId,
        state: values.state,
        binId: values.binId ? values.binId : null,
        price: values.price === '' ? null : Number(values.price),
        notes: values.notes ? values.notes : null,
      };
      return editing && part
        ? updatePart(part.id, payload)
        : createPart(payload);
    },
    onSuccess: (saved) => {
      toast.success(editing ? 'Part updated' : 'Part created');
      queryClient.invalidateQueries({ queryKey: queryKeys.parts.all });
      if (editing) {
        queryClient.setQueryData(queryKeys.parts.detail(saved.id), saved);
      }
      onOpenChange(false);
    },
    onError: (err) => {
      const msg =
        err instanceof ApiRequestError ? err.body.message : 'Could not save part';
      toast.error(msg);
    },
  });

  const onSubmit = (values: PartFormValues) => {
    if (values.price !== '' && values.price !== undefined) {
      const n = Number(values.price);
      if (!Number.isFinite(n) || n < 0) {
        form.setError('price', { message: 'Must be a non-negative number' });
        return;
      }
    }
    mutation.mutate(values);
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-xl">
        <DialogHeader>
          <DialogTitle>{editing ? 'Edit part' : 'New part'}</DialogTitle>
          <DialogDescription>
            {editing
              ? 'Update this part. Changes are logged to its history.'
              : 'Add a part to inventory. Serial numbers must be unique.'}
          </DialogDescription>
        </DialogHeader>

        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-3">
            <div className="grid grid-cols-2 gap-3">
              <FormField
                control={form.control}
                name="serialNumber"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Serial</FormLabel>
                    <FormControl>
                      <Input autoFocus {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <FormField
                control={form.control}
                name="mpn"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>MPN</FormLabel>
                    <FormControl>
                      <Input {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
            </div>

            <FormField
              control={form.control}
              name="manufacturerId"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Manufacturer</FormLabel>
                  <Select value={field.value} onValueChange={field.onChange}>
                    <FormControl>
                      <SelectTrigger>
                        <SelectValue placeholder="Select manufacturer" />
                      </SelectTrigger>
                    </FormControl>
                    <SelectContent>
                      {manufacturers.data?.data.map((m) => (
                        <SelectItem key={m.id} value={m.id}>
                          {m.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <FormMessage />
                </FormItem>
              )}
            />

            <div className="grid grid-cols-2 gap-3">
              <FormField
                control={form.control}
                name="state"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>State</FormLabel>
                    <Select value={field.value} onValueChange={field.onChange}>
                      <FormControl>
                        <SelectTrigger>
                          <SelectValue />
                        </SelectTrigger>
                      </FormControl>
                      <SelectContent>
                        {partStateOptions.map((o) => (
                          <SelectItem key={o.value} value={o.value}>
                            {o.label}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <FormField
                control={form.control}
                name="price"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Price (USD)</FormLabel>
                    <FormControl>
                      <Input type="number" step="0.01" min="0" {...field} />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
            </div>

            <FormField
              control={form.control}
              name="binId"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Location</FormLabel>
                  <Select
                    value={field.value ? field.value : UNASSIGNED}
                    onValueChange={(v) => field.onChange(v === UNASSIGNED ? '' : v)}
                  >
                    <FormControl>
                      <SelectTrigger>
                        <SelectValue placeholder="Unassigned" />
                      </SelectTrigger>
                    </FormControl>
                    <SelectContent>
                      <SelectItem value={UNASSIGNED}>Unassigned</SelectItem>
                      {bins.data?.data.map((b) => (
                        <SelectItem key={b.id} value={b.id}>
                          {b.fullPath ?? b.name}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <FormMessage />
                </FormItem>
              )}
            />

            <FormField
              control={form.control}
              name="notes"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Notes</FormLabel>
                  <FormControl>
                    <Textarea rows={3} {...field} />
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />

            <DialogFooter>
              <Button
                type="button"
                variant="outline"
                onClick={() => onOpenChange(false)}
                disabled={mutation.isPending}
              >
                Cancel
              </Button>
              <Button type="submit" disabled={mutation.isPending}>
                {mutation.isPending && <Loader2 className="h-4 w-4 animate-spin" />}
                {editing ? 'Save changes' : 'Create part'}
              </Button>
            </DialogFooter>
          </form>
        </Form>
      </DialogContent>
    </Dialog>
  );
}
