"use client";
import { useEffect, useRef, useState, type FormEvent } from "react";
import { Check, LoaderCircle, Search, UserRound } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { mutateAuthorization, searchAuthorizationUsers } from "./client-api";
import type { AuthorizationUser } from "./contract";

type SearchState = { term: string; users: AuthorizationUser[]; hasNextPage: boolean; error: string; loading: boolean };
export function AddAuthorizationDialog({ chargepointId, chargepointName, authorizedIds, onOpenChange, onAdded }: {
  chargepointId: string; chargepointName: string; authorizedIds: string[];
  onOpenChange: (open: boolean) => void; onAdded: (user: AuthorizationUser) => void;
}) {
  const [query, setQuery] = useState("");
  const term = query.trim();
  const [search, setSearch] = useState<SearchState>({ term: "", users: [], hasNextPage: false, error: "", loading: false });
  const [selected, setSelected] = useState<AuthorizationUser | null>(null);
  const [saving, setSaving] = useState(false);
  const busy = useRef(false);
  const [error, setError] = useState("");
  const errorRef = useRef<HTMLParagraphElement>(null);
  const eligible = term.length >= 2 && term.length <= 200 && !selected;
  const searching = eligible && (search.term !== term || search.loading);
  const results = eligible && search.term === term ? search.users : [];
  const searchError = eligible && search.term === term ? search.error : "";

  useEffect(() => {
    if (!eligible) return;
    const controller = new AbortController();
    const timer = setTimeout(async () => {
      setSearch({ term, users: [], hasNextPage: false, error: "", loading: true });
      try {
        const result = await searchAuthorizationUsers(chargepointId, term, AbortSignal.any([controller.signal, AbortSignal.timeout(20_000)]));
        if (!controller.signal.aborted) setSearch({ term, ...result, error: "", loading: false });
      } catch (error) {
        if (!controller.signal.aborted) setSearch({ term, users: [], hasNextPage: false, loading: false, error: error instanceof Error ? error.message : "Unable to search users. Try again." });
      }
    }, 300);
    return () => { clearTimeout(timer); controller.abort(); };
  }, [chargepointId, term, eligible]);

  async function submit(event: FormEvent) {
    event.preventDefault();
    if (!selected || busy.current) return;
    if (authorizedIds.includes(selected.id)) { setError("This user is already authorized."); return; }
    busy.current = true;
    setSaving(true);
    setError("");
    try {
      await mutateAuthorization({ chargepointId, userId: selected.id, action: "add" });
      onAdded(selected);
    } catch (error) {
      setError(error instanceof Error ? error.message : "Unable to add authorization. Try again.");
      requestAnimationFrame(() => errorRef.current?.focus());
    } finally { busy.current = false; setSaving(false); }
  }
  return (
    <Dialog open onOpenChange={open => { if (!busy.current) onOpenChange(open); }}>
      <DialogContent showCloseButton={!saving} className="sm:max-w-xl" aria-busy={saving}>
        <DialogHeader>
          <DialogTitle>Add Authorization</DialogTitle>
          <DialogDescription>Select a user to authorize for <span className="font-medium text-foreground">{chargepointName}</span>.</DialogDescription>
        </DialogHeader>
        <form className="space-y-5" onSubmit={submit}>
          <div className="space-y-2">
            <label htmlFor="authorization-user-search" className="field-label">Find a user</label>
            <div className="relative">
              <Search aria-hidden="true" className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
              <Input id="authorization-user-search" className="pl-10" maxLength={200} autoComplete="off" disabled={saving} placeholder="Search by name or email…" aria-describedby="authorization-search-help" value={query} onChange={event => { setQuery(event.target.value); setSelected(null); setError(""); }} />
            </div>
            <p id="authorization-search-help" className="text-xs text-muted-foreground">Enter at least 2 characters to find an active customer.</p>
            {selected ? (
              <div className="flex items-start gap-3 rounded-xl border border-primary/30 bg-primary/5 p-4">
                <Check aria-hidden="true" className="mt-0.5 size-4 shrink-0 text-primary" />
                <div className="min-w-0 flex-1">
                  <p className="font-medium break-words">{selected.name || selected.email || selected.id}</p>
                  <p className="mt-1 break-all text-sm text-muted-foreground">{selected.email || "No email"}</p>
                  <p className="mt-1 break-all text-xs text-muted-foreground">{selected.id}</p>
                </div>
                <Button type="button" size="sm" variant="ghost" disabled={saving} onClick={() => { setSelected(null); setQuery(""); }}>Change</Button>
              </div>
            ) : (
              <div aria-live="polite" aria-busy={searching}>
                {searching && <p role="status" className="flex items-center gap-2 py-3 text-sm text-muted-foreground"><LoaderCircle aria-hidden="true" className="size-4 animate-spin motion-reduce:animate-none" />Searching users…</p>}
                {searchError && <p role="alert" className="py-3 text-sm text-destructive">{searchError}</p>}
                {eligible && !searching && !searchError && !results.length && <p className="rounded-lg border bg-muted/30 p-4 text-sm text-muted-foreground">No users found. Try another name or email.</p>}
                {!!results.length && <div className="max-h-64 overflow-y-auto rounded-xl border" role="group" aria-label="Matching users">
                  {results.map(user => {
                    const authorized = authorizedIds.includes(user.id);
                    return <button key={user.id} type="button" disabled={authorized} className="flex w-full items-center gap-3 border-b p-3 text-left last:border-b-0 hover:bg-muted focus-visible:bg-muted focus-visible:outline-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-60" onClick={() => { setSelected(user); setError(""); }}>
                      <UserRound aria-hidden="true" className="size-4 shrink-0 text-muted-foreground" />
                      <span className="min-w-0 flex-1"><span className="block break-words text-sm font-medium">{user.name || user.email || user.id}</span><span className="block break-all text-xs text-muted-foreground">{user.email || user.id}</span></span>
                      {authorized && <span className="text-xs text-muted-foreground">Already authorized</span>}
                    </button>;
                  })}
                </div>}
                {eligible && !searching && search.hasNextPage && <p className="mt-2 text-xs text-muted-foreground">Showing the first 10 matches. Refine your search to find the right user.</p>}
              </div>
            )}
          </div>
          {error && <p ref={errorRef} tabIndex={-1} role="alert" className="rounded-lg border border-destructive/25 bg-destructive/5 p-3 text-sm text-destructive">{error}</p>}
          <DialogFooter>
            <Button type="button" variant="outline" disabled={saving} onClick={() => onOpenChange(false)}>Cancel</Button>
            <Button type="submit" disabled={!selected || saving}>{saving ? "Adding…" : "Add Authorization"}</Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}
