import { router, usePage } from '@inertiajs/react';
import type { InertiaLinkProps } from '@inertiajs/react';
import {
    Bell,
    CalendarDays,
    ChartColumn,
    LayoutGrid,
    LayoutTemplate,
    Mail,
    MapPin,
    MessageCircleQuestion,
    Package,
    Plug,
    Search,
    Settings,
    Sparkles,
    Tag,
    Truck,
    UserCircle,
    Users,
    Wrench,
} from 'lucide-react';
import * as React from 'react';
import {
    CommandDialog,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList,
    CommandSeparator,
} from '@/components/ui/command';
import { Kbd, KbdGroup } from '@/components/ui/kbd';
import { useBookingDateTimeFormatters } from '@/hooks/use-booking-timezone';
import { toUrl } from '@/lib/utils';
import { dashboard } from '@/routes';
import { search as adminSearch } from '@/routes/admin';
import { index as adminAddons } from '@/routes/admin/addons';
import { index as adminBookings } from '@/routes/admin/bookings';
import { index as adminCustomers } from '@/routes/admin/customers';
import { index as adminDiscounts } from '@/routes/admin/discounts';
import { index as adminFleet } from '@/routes/admin/fleet';
import { index as adminHomepageFaqs } from '@/routes/admin/homepage-faqs';
import { edit as homepageLayout } from '@/routes/admin/homepage-layout';
import { index as adminEmailTemplates } from '@/routes/admin/email-templates';
import { index as adminLocations } from '@/routes/admin/locations';
import { index as adminPackages } from '@/routes/admin/packages';
import { index as adminPlugins } from '@/routes/admin/plugins';
import { index as adminReports } from '@/routes/admin/reports';
import { index as adminSentEmails } from '@/routes/admin/sent-emails';
import { index as adminUsers } from '@/routes/admin/users';
import { index as adminVehicleSizes } from '@/routes/admin/vehicle-sizes';
import { edit as appearance } from '@/routes/appearance';
import { show as bookLocation } from '@/routes/booking/location';
import { show as customerPortal } from '@/routes/customer/portal';
import { edit as profile } from '@/routes/profile';
import { edit as security } from '@/routes/security';
import { index as techJobs, live as techJobsLive } from '@/routes/technician/jobs';
import type { Auth } from '@/types';
import type { UserRole } from '@/types/auth';

// ── Nav items ─────────────────────────────────────────────────────────────────

type NavItem = {
    title: string;
    href: NonNullable<InertiaLinkProps['href']>;
    icon?: React.ComponentType<{ className?: string }>;
    keywords?: string;
};

type NavGroup = {
    label: string;
    items: NavItem[];
};

function hasRole(role: UserRole | undefined, allowed: UserRole[]): boolean {
    return role !== undefined && allowed.includes(role);
}

function getNavGroups(role?: UserRole): NavGroup[] {
    const pages: NavItem[] = [
        { title: 'Dashboard', href: dashboard(), icon: LayoutGrid, keywords: 'home overview' },
    ];

    if (hasRole(role, ['admin', 'manager'])) {
        pages.push(
            { title: 'Bookings', href: adminBookings(), icon: CalendarDays, keywords: 'reservations schedule appointments calendar' },
            { title: 'Reports', href: adminReports(), icon: ChartColumn, keywords: 'analytics stats revenue earnings' },
        );
    }
    if (hasRole(role, ['admin', 'technician'])) {
        pages.push(
            { title: 'Technician Jobs', href: techJobs(), icon: Wrench, keywords: 'work queue tasks service jobs' },
            { title: 'Live Jobs', href: techJobsLive(), icon: Wrench, keywords: 'active current running jobs' },
        );
    }

    const mgmt: NavItem[] = [];
    if (hasRole(role, ['admin'])) {
        mgmt.push({ title: 'Users', href: adminUsers(), icon: Users, keywords: 'staff admin technician accounts team' });
    }
    if (hasRole(role, ['admin', 'manager'])) {
        mgmt.push(
            { title: 'Customers', href: adminCustomers(), icon: Users, keywords: 'clients people accounts members' },
            { title: 'Locations', href: adminLocations(), icon: MapPin, keywords: 'branches offices sites address' },
            { title: 'Packages', href: adminPackages(), icon: Package, keywords: 'services plans pricing wash tiers' },
            { title: 'Add-ons', href: adminAddons(), icon: Package, keywords: 'extras upsell services optional' },
            { title: 'Vehicle Sizes', href: adminVehicleSizes(), icon: Truck, keywords: 'car truck suv size category small large' },
            { title: 'Fleet', href: adminFleet(), icon: Truck, keywords: 'vehicles cars vans equipment mobile' },
            { title: 'Discounts', href: adminDiscounts(), icon: Tag, keywords: 'promo code coupon sale percent off bogo' },
            { title: 'Email Templates', href: adminEmailTemplates(), icon: Mail, keywords: 'notifications messages outreach templates' },
            { title: 'Sent Email Log', href: adminSentEmails(), icon: Mail, keywords: 'outbox history delivered sent' },
            { title: 'Plugins', href: adminPlugins(), icon: Plug, keywords: 'extensions integrations apps modules' },
            { title: 'Homepage Layout', href: homepageLayout(), icon: LayoutTemplate, keywords: 'design website landing page layout' },
            { title: 'Homepage FAQs', href: adminHomepageFaqs(), icon: MessageCircleQuestion, keywords: 'faq questions answers content website help support' },
        );
    }
    if (hasRole(role, ['customer'])) {
        pages.push(
            { title: 'My Portal', href: customerPortal(), icon: UserCircle, keywords: 'account bookings history membership' },
            { title: 'Book a Wash', href: bookLocation(), icon: Sparkles, keywords: 'new booking schedule appointment wash' },
        );
    }

    const settings: NavItem[] = [
        { title: 'Profile Settings', href: profile(), icon: Settings, keywords: 'account name email avatar photo' },
        { title: 'Security Settings', href: security(), icon: Settings, keywords: 'password 2fa passkey login authentication' },
        { title: 'Appearance Settings', href: appearance(), icon: Settings, keywords: 'theme dark light mode color ui' },
    ];

    const groups: NavGroup[] = [{ label: 'Pages', items: pages }];
    if (mgmt.length > 0) groups.push({ label: 'Management', items: mgmt });
    groups.push({ label: 'Settings', items: settings });
    return groups;
}

function matchesQuery(item: NavItem, q: string): boolean {
    const haystack = `${item.title} ${item.keywords ?? ''}`.toLowerCase();
    return q.toLowerCase().split(/\s+/).every((word) => haystack.includes(word));
}

// ── API result types ──────────────────────────────────────────────────────────

type SearchResults = {
    customers: { id: number; name: string; email: string; phone: string | null; url: string }[];
    bookings: {
        id: number;
        uuid: string;
        customer_name: string | null;
        location_name: string | null;
        vehicle_label: string | null;
        scheduled_at: string | null;
        service_status: string;
        url: string;
    }[];
    locations: { id: number; name: string; url: string }[];
    packages: { id: number; name: string; url: string }[];
    users: { id: number; name: string; email: string; role: string; url: string }[];
};

const EMPTY: SearchResults = { customers: [], bookings: [], locations: [], packages: [], users: [] };

function hasAny(r: SearchResults): boolean {
    return r.customers.length > 0 || r.bookings.length > 0 || r.locations.length > 0 || r.packages.length > 0 || r.users.length > 0;
}

// ── Component ─────────────────────────────────────────────────────────────────

export function GlobalSearch() {
    const { formatDateTime } = useBookingDateTimeFormatters();
    const [open, setOpen] = React.useState(false);
    const [query, setQuery] = React.useState('');
    const [results, setResults] = React.useState<SearchResults>(EMPTY);
    const [loading, setLoading] = React.useState(false);

    const { auth } = usePage<{ auth: Auth }>().props;
    const role = auth.user?.role as UserRole | undefined;
    const canSearch = hasRole(role, ['admin', 'manager']);
    const [isMac, setIsMac] = React.useState(false);

    React.useEffect(() => {
        setIsMac(
            /Mac|iPhone|iPad|iPod/.test(navigator.platform) ||
                navigator.userAgent.includes('Mac'),
        );
    }, []);

    // Cmd+K / Ctrl+K
    React.useEffect(() => {
        const onKey = (e: KeyboardEvent) => {
            if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
                e.preventDefault();
                setOpen((p) => !p);
            }
        };
        document.addEventListener('keydown', onKey);
        return () => document.removeEventListener('keydown', onKey);
    }, []);

    // Debounced API fetch
    React.useEffect(() => {
        if (!canSearch || query.length < 2) {
            setResults(EMPTY);
            setLoading(false);
            return;
        }
        setLoading(true);
        const timer = setTimeout(async () => {
            try {
                const url = toUrl(adminSearch()) + '?q=' + encodeURIComponent(query);
                const res = await fetch(url, {
                    headers: { Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
                    credentials: 'same-origin',
                });
                if (res.ok) setResults(await res.json());
            } catch {
                // silent
            } finally {
                setLoading(false);
            }
        }, 300);
        return () => clearTimeout(timer);
    }, [query, canSearch]);

    function handleOpenChange(val: boolean) {
        setOpen(val);
        if (!val) {
            setQuery('');
            setResults(EMPTY);
        }
    }

    const allNavGroups = React.useMemo(() => getNavGroups(role), [role]);

    // When there's a query, filter nav items manually (cmdk filtering is disabled)
    const filteredNavGroups = React.useMemo(() => {
        if (!query.trim()) return allNavGroups;
        return allNavGroups
            .map((g) => ({ ...g, items: g.items.filter((item) => matchesQuery(item, query)) }))
            .filter((g) => g.items.length > 0);
    }, [allNavGroups, query]);

    const hasDataResults = !loading && hasAny(results);
    const searching = canSearch && query.length >= 2;
    const showEmpty = searching && !loading && !hasDataResults && filteredNavGroups.length === 0;

    function go(url: string) {
        handleOpenChange(false);
        router.visit(url);
    }
    function goInertia(href: NonNullable<InertiaLinkProps['href']>) {
        handleOpenChange(false);
        router.visit(toUrl(href));
    }

    return (
        <>
            <button
                type="button"
                onClick={() => setOpen(true)}
                className="flex h-9 w-full items-center gap-2 rounded-md px-2 text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none"
                aria-label="Open search"
            >
                <span className="flex shrink-0 items-center gap-1.5">
                    <Search className="size-4" />
                    <KbdGroup className="hidden sm:inline-flex">
                        <Kbd className="h-auto min-w-0 border-0 bg-transparent px-0 text-muted-foreground/60 shadow-none">
                            {isMac ? '⌘' : 'Ctrl'}
                        </Kbd>
                        <Kbd className="h-auto min-w-0 border-0 bg-transparent px-0 text-muted-foreground/60 shadow-none">
                            K
                        </Kbd>
                    </KbdGroup>
                </span>
                <span className="truncate">Type to search...</span>
            </button>

            <CommandDialog open={open} onOpenChange={handleOpenChange} shouldFilter={false}>
                <CommandInput
                    placeholder="Search customers, bookings, pages..."
                    value={query}
                    onValueChange={setQuery}
                />
                <CommandList>
                    {/* Searching spinner */}
                    {loading && (
                        <div className="py-6 text-center text-sm text-muted-foreground">Searching...</div>
                    )}

                    {/* Nothing found */}
                    {showEmpty && <CommandEmpty>No results for &ldquo;{query}&rdquo;</CommandEmpty>}

                    {/* ── Data results ── */}
                    {hasDataResults && (
                        <>
                            {results.customers.length > 0 && (
                                <CommandGroup heading="Customers">
                                    {results.customers.map((c) => (
                                        <CommandItem key={`c-${c.id}`} onSelect={() => go(c.url)}>
                                            <Users className="mr-2 h-4 w-4 opacity-50" />
                                            <span className="font-medium">{c.name}</span>
                                            <span className="ml-2 truncate text-xs opacity-60">{c.email}</span>
                                        </CommandItem>
                                    ))}
                                </CommandGroup>
                            )}

                            {results.bookings.length > 0 && (
                                <>
                                    {results.customers.length > 0 && <CommandSeparator />}
                                    <CommandGroup heading="Bookings">
                                        {results.bookings.map((b) => (
                                            <CommandItem key={`b-${b.id}`} onSelect={() => go(b.url)}>
                                                <CalendarDays className="mr-2 h-4 w-4 opacity-50" />
                                                <span className="font-mono text-xs opacity-60">#{b.uuid.slice(0, 8).toUpperCase()}</span>
                                                <span className="ml-2 font-medium">{b.customer_name ?? 'Unknown'}</span>
                                                {b.scheduled_at && (
                                                    <span className="ml-2 truncate text-xs opacity-60">{formatDateTime(b.scheduled_at)}</span>
                                                )}
                                                <span className="ml-auto text-xs capitalize opacity-60">
                                                    {b.service_status.replace(/_/g, ' ')}
                                                </span>
                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </>
                            )}

                            {results.users.length > 0 && (
                                <>
                                    {(results.customers.length > 0 || results.bookings.length > 0) && <CommandSeparator />}
                                    <CommandGroup heading="Staff">
                                        {results.users.map((u) => (
                                            <CommandItem key={`u-${u.id}`} onSelect={() => go(u.url)}>
                                                <Users className="mr-2 h-4 w-4 opacity-50" />
                                                <span className="font-medium">{u.name}</span>
                                                <span className="ml-2 text-xs capitalize text-muted-foreground">{u.role}</span>
                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </>
                            )}

                            {results.locations.length > 0 && (
                                <>
                                    {(results.customers.length > 0 || results.bookings.length > 0 || results.users.length > 0) && (
                                        <CommandSeparator />
                                    )}
                                    <CommandGroup heading="Locations">
                                        {results.locations.map((l) => (
                                            <CommandItem key={`l-${l.id}`} onSelect={() => go(l.url)}>
                                                <MapPin className="mr-2 h-4 w-4 opacity-50" />
                                                {l.name}
                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </>
                            )}

                            {results.packages.length > 0 && (
                                <>
                                    {(results.customers.length > 0 || results.bookings.length > 0 || results.users.length > 0 || results.locations.length > 0) && (
                                        <CommandSeparator />
                                    )}
                                    <CommandGroup heading="Packages">
                                        {results.packages.map((p) => (
                                            <CommandItem key={`p-${p.id}`} onSelect={() => go(p.url)}>
                                                <Package className="mr-2 h-4 w-4 opacity-50" />
                                                {p.name}
                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </>
                            )}
                        </>
                    )}

                    {/* ── Nav items ── always shown when no query; shown as fallback when query has no data results */}
                    {!loading && filteredNavGroups.length > 0 && (
                        <>
                            {hasDataResults && <CommandSeparator />}
                            {filteredNavGroups.map((group, i) => (
                                <React.Fragment key={group.label}>
                                    {i > 0 && <CommandSeparator />}
                                    <CommandGroup heading={group.label}>
                                        {group.items.map((item) => (
                                            <CommandItem key={toUrl(item.href)} onSelect={() => goInertia(item.href)}>
                                                {item.icon && <item.icon className="mr-2 h-4 w-4 opacity-60" />}
                                                {item.title}
                                            </CommandItem>
                                        ))}
                                    </CommandGroup>
                                </React.Fragment>
                            ))}
                        </>
                    )}
                </CommandList>
            </CommandDialog>
        </>
    );
}
