import { ChevronsUpDown, Loader2 } from 'lucide-react';
import { useEffect, useId, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { cn } from '@/lib/utils';

const SEARCH_URL = '/admin/chart-of-accounts/search';

export type ChartOfAccountSearchRow = {
    code: string;
    name: string;
};

async function fetchChartOfAccountSearch(params: {
    q?: string;
    code?: string;
    limit?: number;
    signal?: AbortSignal;
}): Promise<ChartOfAccountSearchRow[]> {
    const searchParams = new URLSearchParams();
    if (params.code) {
        searchParams.set('code', params.code);
    } else if (params.q) {
        searchParams.set('q', params.q);
    }
    if (params.limit) {
        searchParams.set('limit', String(params.limit));
    }

    const response = await fetch(`${SEARCH_URL}?${searchParams.toString()}`, {
        headers: {
            Accept: 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
        },
        credentials: 'same-origin',
        signal: params.signal,
    });

    if (!response.ok) {
        throw new Error('Chart of accounts search failed');
    }

    const payload = (await response.json()) as { data: ChartOfAccountSearchRow[] };

    return Array.isArray(payload.data) ? payload.data : [];
}

export function ChartOfAccountCodeDisplay({ code }: { code: string }) {
    const [label, setLabel] = useState<string | null>(null);

    useEffect(() => {
        const trimmed = code.trim();

        if (trimmed === '') {
            setLabel(null);

            return;
        }

        let cancelled = false;

        void (async () => {
            try {
                const rows = await fetchChartOfAccountSearch({ code: trimmed });
                if (cancelled) {
                    return;
                }

                const row = rows[0];
                setLabel(row ? `${row.code} — ${row.name}` : trimmed);
            } catch {
                if (!cancelled) {
                    setLabel(trimmed);
                }
            }
        })();

        return () => {
            cancelled = true;
        };
    }, [code]);

    if (code.trim() === '') {
        return <span className="text-xs text-foreground/90">—</span>;
    }

    if (label === null) {
        return <span className="text-xs tabular-nums text-muted-foreground">{code}</span>;
    }

    return <span className="text-xs text-foreground/90">{label}</span>;
}

type ChartOfAccountAsyncSelectProps = {
    value: string;
    onValueChange: (code: string) => void;
    disabled?: boolean;
    className?: string;
};

export function ChartOfAccountAsyncSelect({
    value,
    onValueChange,
    disabled = false,
    className,
}: ChartOfAccountAsyncSelectProps) {
    const listId = useId();
    const [open, setOpen] = useState(false);
    const [searchQuery, setSearchQuery] = useState('');
    const [results, setResults] = useState<ChartOfAccountSearchRow[]>([]);
    const [searchLoading, setSearchLoading] = useState(false);
    const [resolved, setResolved] = useState<ChartOfAccountSearchRow | null>(null);
    const [resolveLoading, setResolveLoading] = useState(false);

    useEffect(() => {
        const trimmed = value.trim();

        if (trimmed === '') {
            setResolved(null);
            setResolveLoading(false);

            return;
        }

        let cancelled = false;
        setResolveLoading(true);

        void (async () => {
            try {
                const rows = await fetchChartOfAccountSearch({ code: trimmed });
                if (cancelled) {
                    return;
                }

                setResolved(rows[0] ?? { code: trimmed, name: '' });
            } catch {
                if (!cancelled) {
                    setResolved({ code: trimmed, name: '' });
                }
            } finally {
                if (!cancelled) {
                    setResolveLoading(false);
                }
            }
        })();

        return () => {
            cancelled = true;
        };
    }, [value]);

    useEffect(() => {
        if (!open) {
            return;
        }

        const q = searchQuery.trim();

        if (q.length < 2) {
            setResults([]);
            setSearchLoading(false);

            return;
        }

        const controller = new AbortController();
        setSearchLoading(true);

        const timer = window.setTimeout(() => {
            void (async () => {
                try {
                    const rows = await fetchChartOfAccountSearch({ q, limit: 25, signal: controller.signal });
                    if (!controller.signal.aborted) {
                        setResults(rows);
                    }
                } catch (error) {
                    if (error instanceof DOMException && error.name === 'AbortError') {
                        return;
                    }

                    if (!controller.signal.aborted) {
                        setResults([]);
                    }
                } finally {
                    if (!controller.signal.aborted) {
                        setSearchLoading(false);
                    }
                }
            })();
        }, 280);

        return () => {
            window.clearTimeout(timer);
            controller.abort();
            setSearchLoading(false);
        };
    }, [open, searchQuery]);

    const triggerLabel = (() => {
        const trimmed = value.trim();

        if (trimmed === '') {
            return null;
        }

        if (resolveLoading && !resolved) {
            return trimmed;
        }

        if (resolved) {
            return resolved.name.trim() === '' ? resolved.code : `${resolved.code} — ${resolved.name}`;
        }

        return trimmed;
    })();

    return (
        <Popover
            open={open}
            onOpenChange={(next) => {
                setOpen(next);
                if (!next) {
                    setSearchQuery('');
                    setResults([]);
                }
            }}
        >
            <PopoverTrigger asChild>
                <Button
                    type="button"
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    aria-controls={listId}
                    disabled={disabled}
                    className={cn(
                        'h-9 w-full max-w-[14rem] justify-between gap-1 px-2 font-normal',
                        !triggerLabel && 'text-muted-foreground',
                        className,
                    )}
                >
                    <span className="min-w-0 flex-1 truncate text-left text-sm">{triggerLabel ?? 'Selecteaza cont'}</span>
                    {resolveLoading ? (
                        <Loader2 className="h-4 w-4 shrink-0 animate-spin opacity-60" aria-hidden />
                    ) : (
                        <ChevronsUpDown className="h-4 w-4 shrink-0 opacity-50" aria-hidden />
                    )}
                </Button>
            </PopoverTrigger>
            <PopoverContent align="start" className="w-80 p-2">
                <div className="flex flex-col gap-2">
                    <Input
                        autoComplete="off"
                        placeholder="Cauta dupa cod sau denumire (min. 2 caractere)"
                        value={searchQuery}
                        onChange={(event) => setSearchQuery(event.target.value)}
                        disabled={disabled}
                    />
                    {value.trim() !== '' ? (
                        <Button
                            type="button"
                            variant="ghost"
                            size="sm"
                            className="h-8 justify-start px-2 text-muted-foreground"
                            disabled={disabled}
                            onClick={() => {
                                onValueChange('');
                                setResolved(null);
                                setOpen(false);
                            }}
                        >
                            Fara cont selectat
                        </Button>
                    ) : null}
                    <div
                        id={listId}
                        role="listbox"
                        className="max-h-56 overflow-y-auto rounded-md border border-border/60 bg-background"
                    >
                        {searchLoading ? (
                            <div className="flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground">
                                <Loader2 className="h-4 w-4 animate-spin" aria-hidden />
                                Se incarca...
                            </div>
                        ) : searchQuery.trim().length > 0 && searchQuery.trim().length < 2 ? (
                            <p className="px-2 py-4 text-center text-xs text-muted-foreground">
                                Introdu cel putin 2 caractere pentru cautare.
                            </p>
                        ) : results.length === 0 ? (
                            <p className="px-2 py-4 text-center text-xs text-muted-foreground">
                                {searchQuery.trim().length >= 2 ? 'Niciun rezultat.' : 'Scrie pentru a cauta conturi.'}
                            </p>
                        ) : (
                            <ul className="divide-y divide-dashed divide-border/60 p-1">
                                {results.map((row) => (
                                    <li key={row.code}>
                                        <button
                                            type="button"
                                            role="option"
                                            aria-selected={row.code === value.trim()}
                                            className={cn(
                                                'w-full cursor-pointer rounded-sm px-2 py-1.5 text-left text-sm hover:bg-muted',
                                                row.code === value.trim() && 'bg-muted/80',
                                            )}
                                            onClick={() => {
                                                onValueChange(row.code);
                                                setResolved(row);
                                                setOpen(false);
                                            }}
                                        >
                                            <span className="font-mono text-xs tabular-nums text-foreground/90">{row.code}</span>
                                            <span className="mt-0.5 block text-xs leading-snug text-muted-foreground">{row.name}</span>
                                        </button>
                                    </li>
                                ))}
                            </ul>
                        )}
                    </div>
                </div>
            </PopoverContent>
        </Popover>
    );
}
