import { useEffect } from "react";
import { useForm } from "@tanstack/react-form";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { z } from "zod";

import type { Client } from "@rubis/shared";
import { api, ApiError } from "@/lib/api";
import { queryKeys } from "@/lib/queryKeys";

import { Button } from "@/components/ui/Button";
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/Dialog";
import { Field } from "@/components/ui/Field";
import { Input } from "@/components/ui/Input";
import { Textarea } from "@/components/ui/Textarea";

/**
 * Création manuelle d'un client depuis /clients.
 *
 * Différent de la création implicite via la saisie de facture (où on crée
 * un client à la volée à partir du nom tapé) : ici l'utilisateur peut
 * pré-remplir tous les champs en amont.
 *
 * Validation :
 *  - name requis (≥ 2 chars)
 *  - email REQUIS (Rubis sans email = produit cassé : aucune relance ne part)
 *  - siret optionnel mais validé si fourni (14 chiffres)
 *  - phone, address, notes optionnels
 *
 * Le serveur renvoie 409 si un client de même nom existe déjà — on toast
 * un message contextuel sans bloquer brutalement.
 */

type FormValues = {
  name: string;
  email: string;
  contactFirstName: string;
  contactLastName: string;
  phone: string;
  address: string;
  siret: string;
  notes: string;
};

const validators = {
  name: z.string().min(2, "Au moins 2 caractères").max(120, "120 caractères max"),
  // Email REQUIS : sans canal de communication actif, Rubis ne peut pas
  // tenir sa promesse de relances automatiques.
  email: z
    .string()
    .min(1, "Email requis")
    .max(120)
    .email("Format d'email invalide"),
  // SIRET optionnel — vide accepté, sinon 14 chiffres exactement.
  siret: z
    .string()
    .refine(
      (v) => v === "" || /^\d{14}$/u.test(v),
      "14 chiffres exactement (ou laissez vide)",
    ),
};

type ClientCreateDialogProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  /** Pré-remplit le nom (utile si le user a déjà tapé qq chose ailleurs). */
  defaultName?: string;
  /** Callback optionnel après création réussie. */
  onCreated?: (client: Client) => void;
};

export function ClientCreateDialog({
  open,
  onOpenChange,
  defaultName = "",
  onCreated,
}: ClientCreateDialogProps) {
  const queryClient = useQueryClient();

  const createMutation = useMutation({
    mutationFn: (input: FormValues) =>
      api.post<Client>("/api/v1/clients", {
        name: input.name.trim(),
        email: input.email.trim(),
        contactFirstName:
          input.contactFirstName.trim() === "" ? null : input.contactFirstName.trim(),
        contactLastName:
          input.contactLastName.trim() === "" ? null : input.contactLastName.trim(),
        phone: input.phone.trim() === "" ? null : input.phone.trim(),
        address: input.address.trim() === "" ? null : input.address.trim(),
        siret: input.siret.trim() === "" ? null : input.siret.trim(),
        notes: input.notes.trim() === "" ? null : input.notes.trim(),
      }),
    onSuccess: (client) => {
      void queryClient.invalidateQueries({ queryKey: queryKeys.clients.all() });
      toast.success(`${client.name} ajouté à votre carnet.`);
      onCreated?.(client);
      onOpenChange(false);
    },
    onError: (error: unknown) => {
      if (error instanceof ApiError && error.status === 409) {
        // Doublon — le serveur le mentionne dans le message
        toast.error(error.message);
        return;
      }
      toast.error("Création impossible. Vérifiez les champs.");
    },
  });

  const initialValues: FormValues = {
    name: defaultName,
    email: "",
    contactFirstName: "",
    contactLastName: "",
    phone: "",
    address: "",
    siret: "",
    notes: "",
  };

  const form = useForm({
    defaultValues: initialValues,
    onSubmit: async ({ value }) => {
      // Validation finale avant submit (les validators par champ couvrent
      // déjà l'inline mais on re-check au cas où).
      const checks: Array<[z.ZodTypeAny, string]> = [
        [validators.name, value.name],
        [validators.email, value.email],
        [validators.siret, value.siret],
      ];
      for (const [schema, val] of checks) {
        const r = schema.safeParse(val);
        if (!r.success) {
          toast.error(r.error.issues[0]?.message ?? "Champ invalide");
          return;
        }
      }
      await createMutation.mutateAsync(value);
    },
  });

  // Reset à chaque ouverture pour avoir un form propre.
  useEffect(() => {
    if (open) form.reset({ ...initialValues, name: defaultName });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, defaultName]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent maxWidth={520}>
        <DialogHeader>
          <DialogTitle>Nouveau client</DialogTitle>
          <DialogDescription>
            Ajoutez une fiche client pour préparer le terrain avant la
            prochaine facture.
          </DialogDescription>
        </DialogHeader>

        <form
          noValidate
          onSubmit={(e) => {
            e.preventDefault();
            void form.handleSubmit();
          }}
          className="flex flex-col gap-5"
        >
          <form.Field name="name" validators={{ onChange: validators.name }}>
            {(field) => (
              <Field
                label="Nom du client"
                htmlFor={field.name}
                error={firstError(field.state.meta.errors)}
              >
                <Input
                  id={field.name}
                  autoFocus
                  placeholder="Boulangerie Martin SARL"
                  value={field.state.value}
                  onChange={(e) => field.handleChange(e.target.value)}
                />
              </Field>
            )}
          </form.Field>

          <form.Field name="email" validators={{ onChange: validators.email }}>
            {(field) => (
              <Field
                label="Email du contact"
                htmlFor={field.name}
                hint="Destinataire des relances. Préférez une adresse générique (compta@, facturation@) à une nominative."
                error={firstError(field.state.meta.errors)}
              >
                <Input
                  id={field.name}
                  type="email"
                  autoComplete="off"
                  placeholder="compta@entreprise.fr"
                  value={field.state.value}
                  onChange={(e) => field.handleChange(e.target.value)}
                />
              </Field>
            )}
          </form.Field>

          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
            <form.Field name="contactFirstName">
              {(field) => (
                <Field
                  label="Prénom du contact"
                  htmlFor={field.name}
                  hint="Optionnel. Permet de personnaliser les relances ({{client.contactFirstName}})."
                >
                  <Input
                    id={field.name}
                    autoComplete="off"
                    placeholder="Marie"
                    value={field.state.value}
                    onChange={(e) => field.handleChange(e.target.value)}
                  />
                </Field>
              )}
            </form.Field>
            <form.Field name="contactLastName">
              {(field) => (
                <Field label="Nom du contact" htmlFor={field.name} hint="Optionnel.">
                  <Input
                    id={field.name}
                    autoComplete="off"
                    placeholder="Martin"
                    value={field.state.value}
                    onChange={(e) => field.handleChange(e.target.value)}
                  />
                </Field>
              )}
            </form.Field>
          </div>

          <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
            <form.Field name="phone">
              {(field) => (
                <Field label="Téléphone" htmlFor={field.name} hint="Optionnel.">
                  <Input
                    id={field.name}
                    type="tel"
                    autoComplete="off"
                    placeholder="+33 …"
                    value={field.state.value}
                    onChange={(e) => field.handleChange(e.target.value)}
                  />
                </Field>
              )}
            </form.Field>
            <form.Field
              name="siret"
              validators={{ onChange: validators.siret }}
            >
              {(field) => (
                <Field
                  label="SIRET"
                  htmlFor={field.name}
                  hint="14 chiffres. Recommandé pour les mises en demeure."
                  error={firstError(field.state.meta.errors)}
                >
                  <Input
                    id={field.name}
                    type="text"
                    inputMode="numeric"
                    autoComplete="off"
                    placeholder="123 456 789 00012"
                    value={field.state.value}
                    onChange={(e) =>
                      field.handleChange(e.target.value.replace(/\s/gu, ""))
                    }
                  />
                </Field>
              )}
            </form.Field>
          </div>

          <form.Field name="address">
            {(field) => (
              <Field
                label="Adresse postale"
                htmlFor={field.name}
                hint="Optionnelle, mais requise pour les mises en demeure formelles."
              >
                <Input
                  id={field.name}
                  autoComplete="off"
                  placeholder="12 rue …"
                  value={field.state.value}
                  onChange={(e) => field.handleChange(e.target.value)}
                />
              </Field>
            )}
          </form.Field>

          <form.Field name="notes">
            {(field) => (
              <Field
                label="Notes internes"
                htmlFor={field.name}
                hint="Visible uniquement par vous, jamais envoyé."
              >
                <Textarea
                  id={field.name}
                  rows={3}
                  placeholder="Préférences de paiement, contexte, anecdotes…"
                  value={field.state.value}
                  onChange={(e) => field.handleChange(e.target.value)}
                />
              </Field>
            )}
          </form.Field>

          <DialogFooter>
            <DialogClose asChild>
              <Button variant="secondary" size="sm" type="button">
                Annuler
              </Button>
            </DialogClose>
            <Button
              size="sm"
              type="submit"
              loading={createMutation.isPending}
            >
              Créer le client
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}

function firstError(errors: unknown[]): string | undefined {
  const first = errors[0];
  if (!first) return undefined;
  if (typeof first === "string") return first;
  if (typeof first === "object" && first !== null && "message" in first) {
    const msg = (first as { message?: unknown }).message;
    if (typeof msg === "string") return msg;
  }
  return undefined;
}
