import { useMemo, useRef, useState } from "react";
import { Check, Loader2, UserPlus } from "lucide-react";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from "@/components/ui/command";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useTravelerSearch } from "@/hooks/useTravelerSearch";
import { useTrips } from "@/contexts/TripContext";
import { assignExistingTravelerToTrip, isTravelerAlreadyLinked, normalizeTravelerEmail } from "@/services/travelerActions";
import { inviteTraveler } from "@/services/invitationService";
import type { TripMember } from "@/types";
import { toast } from "sonner";

export function AddTravelerDialog({ open, onOpenChange, tripId, members, invitationEmails }: { open: boolean; onOpenChange: (open: boolean) => void; tripId: string; members: TripMember[]; invitationEmails: string[] }) {
  const { travelers, loading } = useTravelerSearch();
  const { refetchTrips } = useTrips();
  const [query, setQuery] = useState("");
  const [creating, setCreating] = useState(false);
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [busyId, setBusyId] = useState<string | null>(null);
  const lock = useRef(false);
  const linkedEmails = [...members.map((member) => member.email), ...invitationEmails];
  const results = useMemo(() => { const needle = query.trim().toLowerCase(); return travelers.filter((traveler) => !needle || traveler.name.toLowerCase().includes(needle) || traveler.email.toLowerCase().includes(needle)); }, [query, travelers]);

  const finish = (message: string) => { refetchTrips(); toast.success(message); setQuery(""); setCreating(false); setName(""); setEmail(""); setError(null); onOpenChange(false); };
  const assign = async (traveler: (typeof travelers)[number]) => {
    if (!traveler.id || lock.current || isTravelerAlreadyLinked(traveler.email, linkedEmails)) return;
    lock.current = true; setBusyId(traveler.id); setError(null);
    try { await assignExistingTravelerToTrip(tripId, traveler.id); finish(`${traveler.name} a été ajouté au voyage.`); }
    catch (cause) { console.error(cause); setError("Impossible d’ajouter cette personne. Vérifiez son accès puis réessayez."); }
    finally { lock.current = false; setBusyId(null); }
  };
  const createAndInvite = async () => {
    const normalizedEmail = normalizeTravelerEmail(email);
    if (lock.current) return;
    if (name.trim().length < 2 || !/^\S+@\S+\.\S+$/.test(normalizedEmail)) { setError("Indiquez un nom et une adresse email valide."); return; }
    if (isTravelerAlreadyLinked(normalizedEmail, linkedEmails)) { setError("Cette personne participe déjà au voyage ou possède une invitation active."); return; }
    lock.current = true; setBusyId("new"); setError(null);
    try { const result = await inviteTraveler({ tripId, email: normalizedEmail, travelerName: name.trim() }); finish(result?.associated ? `${name.trim()} utilise déjà TripTales et a été ajouté au voyage.` : `Invitation envoyée à ${normalizedEmail}.`); }
    catch (cause) { console.error(cause); setError(cause instanceof Error ? cause.message : "Impossible d’envoyer l’invitation. Réessayez."); }
    finally { lock.current = false; setBusyId(null); }
  };

  return <Dialog open={open} onOpenChange={(next) => { if (!lock.current) onOpenChange(next); }}><DialogContent className="overflow-hidden p-0 sm:max-w-xl"><DialogHeader className="px-5 pt-5"><DialogTitle>Ajouter un voyageur</DialogTitle><DialogDescription>Ajoutez un client existant ou envoyez un accès à une nouvelle personne.</DialogDescription></DialogHeader>
    {!creating ? <Command shouldFilter={false}><CommandInput autoFocus placeholder="Rechercher par nom ou adresse email…" value={query} onValueChange={setQuery} /><CommandList className="max-h-[55vh]"><CommandEmpty>{loading ? "Chargement des clients…" : `Aucun client trouvé${query ? ` pour « ${query} »` : ""}.`}</CommandEmpty><CommandGroup heading={query ? "Résultats" : "Clients disponibles"}>{results.map((traveler) => { const linked = isTravelerAlreadyLinked(traveler.email, linkedEmails); return <CommandItem key={traveler.id || traveler.email} disabled={linked || !traveler.id} value={`${traveler.name} ${traveler.email}`} onSelect={() => void assign(traveler)}><span className="min-w-0 flex-1"><span className="block truncate font-medium">{traveler.name}</span><span className="block truncate text-xs text-muted-foreground">{traveler.email}</span></span>{busyId === traveler.id ? <Loader2 className="h-4 w-4 animate-spin" /> : linked ? <span className="text-xs text-muted-foreground">Déjà dans ce voyage</span> : <Check className="h-4 w-4 opacity-0" />}</CommandItem>; })}</CommandGroup><CommandSeparator /><CommandGroup><CommandItem onSelect={() => { setCreating(true); if (query.includes("@")) setEmail(query); }} className="text-primary"><UserPlus className="mr-2 h-4 w-4" />Créer un nouveau voyageur</CommandItem></CommandGroup></CommandList></Command> : <form className="space-y-4 px-5 pb-5" onSubmit={(event) => { event.preventDefault(); void createAndInvite(); }}><div><Label htmlFor="new-traveler-name">Nom complet</Label><Input id="new-traveler-name" autoFocus value={name} onChange={(event) => setName(event.target.value)} /></div><div><Label htmlFor="new-traveler-email">Email</Label><Input id="new-traveler-email" type="email" value={email} onChange={(event) => setEmail(event.target.value)} /></div><p className="text-sm text-muted-foreground">La personne sera ajoutée au voyage si elle utilise déjà TripTales. Sinon, elle recevra une invitation.</p><div className="flex justify-end gap-2"><Button type="button" variant="ghost" onClick={() => { setCreating(false); setError(null); }}>Retour</Button><Button type="submit" disabled={busyId === "new"}>{busyId === "new" ? <><Loader2 className="mr-2 h-4 w-4 animate-spin" />Envoi…</> : "Ajouter et inviter"}</Button></div></form>}
    {error && <div role="alert" className="mx-5 mb-5 rounded-md bg-destructive/10 p-3 text-sm text-destructive">{error}</div>}
  </DialogContent></Dialog>;
}
