import { useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import {
    FolderGit2,
    GitPullRequest,
    Hexagon,
    MessageSquare,
    Search,
    Users,
    Loader2,
} from 'lucide-react';
import { client } from '@/client/client.gen';
import { messageSearch, search, searchMessages } from '@/client/sdk.gen';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
import { formatDistanceToNow, parseISO } from 'date-fns';
import type {
    ProjectSearchItem,
    RepoSearchItem,
    IssueSearchItem,
    UserSearchItem,
    MessageSearchResponse,
    RoomMessageResponse,
    SearchResponse,
    GlobalMessageSearchResponse,
    GlobalMessageSearchItem,
} from '@/client/types.gen';

// ─── Helpers ──────────────────────────────────────────────────────────────────

const ALL_TYPES = ['projects', 'repos', 'issues', 'users', 'messages'] as const;
type SearchType = typeof ALL_TYPES[number];

const TYPE_LABELS: Record<SearchType, string> = {
    projects: 'Projects',
    repos: 'Repositories',
    issues: 'Issues',
    users: 'Users',
    messages: 'Messages',
};

const TYPE_ICONS: Record<SearchType, React.ComponentType<{ className?: string }>> = {
    projects: Hexagon,
    repos: FolderGit2,
    issues: GitPullRequest,
    users: Users,
    messages: MessageSquare,
};

function getTotal(results: SearchResponse): number {
    return [results.projects, results.repos, results.issues, results.users]
        .filter(Boolean)
        .reduce((sum, r) => sum + (r?.total ?? 0), 0);
}

// ─── Sub-components ───────────────────────────────────────────────────────────

function ProjectItem({ item }: { item: ProjectSearchItem }) {
    return (
        <a
            href={`/project/${item.name}`}
            className="flex items-start gap-3 rounded-md p-3 hover:bg-muted/50 transition-colors -mx-3"
        >
            <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary font-semibold text-sm">
                {item.display_name?.charAt(0)?.toUpperCase() ?? 'P'}
            </div>
            <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                    <span className="font-semibold text-sm hover:underline">{item.display_name || item.name}</span>
                    <span className="text-xs text-muted-foreground truncate">{item.name}</span>
                    <Badge variant={item.is_public ? 'default' : 'secondary'} className="text-xs shrink-0">
                        {item.is_public ? 'Public' : 'Private'}
                    </Badge>
                </div>
                {item.description && (
                    <p className="text-xs text-muted-foreground mt-0.5 line-clamp-1">{item.description}</p>
                )}
                <p className="text-xs text-muted-foreground mt-1">
                    Updated {formatDistanceToNow(parseISO(item.updated_at), { addSuffix: true })}
                </p>
            </div>
        </a>
    );
}

function RepoItem({ item }: { item: RepoSearchItem }) {
    return (
        <a
            href={`/repository/${item.project_name}/${item.name}`}
            className="flex items-start gap-3 rounded-md p-3 hover:bg-muted/50 transition-colors -mx-3"
        >
            <FolderGit2 className="h-9 w-9 shrink-0 text-muted-foreground" />
            <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                    <span className="font-semibold text-sm hover:underline">{item.name}</span>
                    <span className="text-xs text-muted-foreground truncate">{item.project_name}</span>
                    <Badge variant={item.is_private ? 'secondary' : 'outline'} className="text-xs shrink-0">
                        {item.is_private ? 'Private' : 'Public'}
                    </Badge>
                </div>
                {item.description && (
                    <p className="text-xs text-muted-foreground mt-0.5 line-clamp-1">{item.description}</p>
                )}
            </div>
        </a>
    );
}

function IssueItem({ item }: { item: IssueSearchItem }) {
    return (
        <a
            href={`/project/${item.project_name}/issues/${item.number}`}
            className="flex items-start gap-3 rounded-md p-3 hover:bg-muted/50 transition-colors -mx-3"
        >
            <GitPullRequest className="h-9 w-9 shrink-0 text-muted-foreground" />
            <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                    <span className="font-semibold text-sm hover:underline">{item.title}</span>
                    <span className="text-xs text-muted-foreground shrink-0">#{item.number}</span>
                    <Badge
                        variant={item.state === 'open' ? 'default' : 'secondary'}
                        className={cn('text-xs shrink-0', item.state === 'open' ? 'bg-green-500/20 text-green-700 dark:bg-green-500/30 dark:text-green-400 border-green-500/30' : '')}
                    >
                        {item.state}
                    </Badge>
                </div>
                <p className="text-xs text-muted-foreground mt-0.5">
                    {item.project_name} · Updated {formatDistanceToNow(parseISO(item.updated_at), { addSuffix: true })}
                </p>
            </div>
        </a>
    );
}

function UserItem({ item }: { item: UserSearchItem }) {
    return (
        <a
            href={`/user/${item.username}`}
            className="flex items-start gap-3 rounded-md p-3 hover:bg-muted/50 transition-colors -mx-3"
        >
            <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary font-semibold text-sm">
                {item.display_name?.charAt(0)?.toUpperCase() ?? item.username.charAt(0).toUpperCase()}
            </div>
            <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                    <span className="font-semibold text-sm hover:underline">{item.display_name || item.username}</span>
                    <span className="text-xs text-muted-foreground">@{item.username}</span>
                </div>
                {item.organization && (
                    <p className="text-xs text-muted-foreground mt-0.5">{item.organization}</p>
                )}
            </div>
        </a>
    );
}

type MessageSearchItem = RoomMessageResponse | GlobalMessageSearchItem;

function isGlobalMessage(item: MessageSearchItem): item is GlobalMessageSearchItem {
    return 'room_id' in item && 'room_name' in item;
}

function MessageItem({ item }: { item: MessageSearchItem }) {
    const isGlobal = isGlobalMessage(item);
    const roomLabel = isGlobal ? item.room_name : item.room;
    const roomHref = isGlobal
        ? `/rooms/${item.room_id}`
        : `/project/${item.room.split(':')[0]}/room/${item.room.split(':')[1] ?? item.room}`;
    const displayContent = isGlobal ? (item.highlighted_content ?? item.content) : item.content;

    return (
        <a
            href={roomHref}
            className="flex items-start gap-3 rounded-md p-3 hover:bg-muted/50 transition-colors -mx-3"
        >
            <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary font-semibold text-sm">
                {(item.display_name ?? item.sender_id ?? '?')[0]?.toUpperCase()}
            </div>
            <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                    <span className="font-semibold text-sm hover:underline">
                        {item.display_name ?? item.sender_id ?? 'Unknown'}
                    </span>
                    <Badge variant="secondary" className="text-xs shrink-0 truncate max-w-[120px]">
                        {roomLabel}
                    </Badge>
                    <span className="text-xs text-muted-foreground ml-auto shrink-0">
                        {formatDistanceToNow(parseISO(item.send_at), { addSuffix: true })}
                    </span>
                </div>
                <p
                    className="text-xs mt-0.5 line-clamp-2 whitespace-pre-wrap"
                    style={{ color: 'var(--muted-foreground)' }}
                    dangerouslySetInnerHTML={{ __html: displayContent }}
                />
            </div>
        </a>
    );
}

function ResultSection<T>({
    type,
    result,
    renderer,
}: {
    type: SearchType;
    result: { items: T[]; total: number; page: number; per_page: number } | null;
    renderer: (item: T) => React.ReactNode;
}) {
    const Icon = TYPE_ICONS[type];
    const label = TYPE_LABELS[type];
    if (!result || result.items.length === 0) return null;

    return (
        <Card>
            <CardHeader className="pb-3">
                <CardTitle className="flex items-center gap-2 text-sm">
                    <Icon className="h-4 w-4" />
                    {label}
                    <Badge variant="secondary" className="ml-auto text-xs">{result.total}</Badge>
                </CardTitle>
            </CardHeader>
            <CardContent className="divide-y">
                {result.items.map((item) => (
                    <div key={(item as { uid?: string; number?: number }).uid ?? (item as { number?: number }).number}>
                        {renderer(item)}
                    </div>
                ))}
                {result.items.length < result.total && (
                    <p className="px-3 py-2 text-xs text-muted-foreground text-center">
                        Showing {result.items.length} of {result.total} {label.toLowerCase()}
                    </p>
                )}
            </CardContent>
        </Card>
    );
}

// ─── Main page ────────────────────────────────────────────────────────────────

export default function SearchPage() {
    const [searchParams, setSearchParams] = useSearchParams();
    const [roomIdInput, setRoomIdInput] = useState('');

    const q = searchParams.get('q') ?? '';
    const typeParam = searchParams.get('type') ?? '';
    const page = parseInt(searchParams.get('page') ?? '1', 10);
    const perPage = 20;

    // Parse active types from query param
    const activeTypes: SearchType[] = typeParam
        ? (typeParam.split(',').filter((t): t is SearchType => ALL_TYPES.includes(t as SearchType)))
        : [...ALL_TYPES];

    const showMessages = activeTypes.includes('messages');
    const useRoomScoped = roomIdInput.trim().length > 0;

    const { data, isLoading, error } = useQuery({
        queryKey: ['search', q, typeParam, page],
        queryFn: async () => {
            const resp = await search({
                client,
                query: {
                    q,
                    page,
                    per_page: perPage,
                    ...(typeParam ? { type: typeParam } : {}),
                },
            });
            return resp.data!.data as SearchResponse;
        },
        enabled: q.trim().length > 0,
    });

    // Global message search across all accessible rooms
    const { data: globalMessagesData, isLoading: globalMessagesLoading } = useQuery({
        queryKey: ['search-messages-global', q],
        queryFn: async () => {
            const resp = await searchMessages({
                query: { q, page: 1, per_page: 20 },
            });
            return resp.data?.data as GlobalMessageSearchResponse;
        },
        enabled: q.trim().length > 0 && showMessages && !useRoomScoped,
    });

    // Room-scoped message search (when room ID is explicitly provided)
    const { data: roomMessagesData, isLoading: roomMessagesLoading } = useQuery({
        queryKey: ['search-messages-room', q, roomIdInput],
        queryFn: async () => {
            const resp = await messageSearch({
                path: { room_id: roomIdInput.trim() },
                query: { q, limit: 20 },
            });
            return resp.data?.data as MessageSearchResponse;
        },
        enabled: q.trim().length > 0 && showMessages && useRoomScoped,
    });

    const messagesData = useRoomScoped ? roomMessagesData : globalMessagesData;
    const messagesLoading = useRoomScoped ? roomMessagesLoading : globalMessagesLoading;

    const results = data ?? null;

    function handleSearchSubmit(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        const fd = new FormData(e.currentTarget);
        const newQ = fd.get('q') as string;
        if (newQ.trim()) {
            setSearchParams({ q: newQ.trim(), type: typeParam });
        }
    }

    function toggleType(t: SearchType) {
        let next: SearchType[];
        if (activeTypes.includes(t)) {
            next = activeTypes.filter((x) => x !== t);
        } else {
            next = [...activeTypes, t];
        }
        if (next.length === 0) next = [...ALL_TYPES];
        setSearchParams({ q, type: next.join(','), page: '1' });
    }

    return (
        <div className="flex-1 overflow-y-auto">
            {/* Search header */}
            <div className="border-b bg-background/80 backdrop-blur-sm sticky top-0 z-10">
                <div className="mx-auto max-w-3xl px-6 py-4">
                    <form onSubmit={handleSearchSubmit} className="flex gap-2">
                        <div className="relative flex-1">
                            <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
                            <Input
                                name="q"
                                defaultValue={q}
                                placeholder="Search projects, repositories, issues, users..."
                                className="pl-9 h-10"
                                autoFocus
                            />
                        </div>
                        <Button type="submit">Search</Button>
                    </form>

                    {/* Type filters */}
                    <div className="flex items-center gap-1 mt-3">
                        {ALL_TYPES.map((t) => {
                            const Icon = TYPE_ICONS[t];
                            const active = activeTypes.includes(t);
                            return (
                                <Button
                                    key={t}
                                    variant={active ? 'default' : 'outline'}
                                    size="sm"
                                    className="gap-1.5 h-7 text-xs"
                                    onClick={() => toggleType(t)}
                                >
                                    <Icon className="h-3.5 w-3.5" />
                                    {TYPE_LABELS[t]}
                                </Button>
                            );
                        })}
                    </div>

                    {/* Room ID input for messages search */}
                    {showMessages && (
                        <div className="mt-2">
                            <Input
                                placeholder="Room ID to search messages in (e.g. workspace:general)..."
                                value={roomIdInput}
                                onChange={(e) => setRoomIdInput(e.target.value)}
                                className="h-8 text-xs"
                            />
                        </div>
                    )}
                </div>
            </div>

            {/* Results */}
            <div className="mx-auto max-w-3xl px-6 py-6">
                {isLoading && !showMessages && (
                    <div className="flex items-center justify-center py-24">
                        <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
                    </div>
                )}

                {error && (
                    <div className="text-center py-16 text-muted-foreground">
                        <Search className="h-10 w-10 mx-auto mb-3 opacity-20" />
                        <p className="text-sm font-medium">Search failed</p>
                        <p className="text-xs mt-1">{error.message}</p>
                    </div>
                )}

                {!isLoading && !error && !q.trim() && (
                    <div className="text-center py-24">
                        <Search className="h-12 w-12 mx-auto mb-4 text-muted-foreground/20" />
                        <p className="text-muted-foreground text-sm">Enter a keyword to search across all content.</p>
                    </div>
                )}

                {!isLoading && !error && results && q.trim() && (
                    <>
                        <div className="mb-4 flex items-center justify-between">
                            <p className="text-sm text-muted-foreground">
                                {results && getTotal(results) > 0
                                    ? `${getTotal(results)} results for "${q}"`
                                    : showMessages && messagesData
                                    ? `${messagesData.total} message${messagesData.total === 1 ? '' : 's'} for "${q}"${useRoomScoped ? ` in room ${roomIdInput}` : ' across all accessible rooms'}`
                                    : `No results for "${q}"`}
                            </p>
                        </div>

                        <div className="space-y-6">
                            {activeTypes.includes('projects') && (
                                <ResultSection
                                    type="projects"
                                    result={results?.projects ?? null}
                                    renderer={(item) => <ProjectItem item={item} />}
                                />
                            )}
                            {activeTypes.includes('repos') && (
                                <ResultSection
                                    type="repos"
                                    result={results?.repos ?? null}
                                    renderer={(item) => <RepoItem item={item} />}
                                />
                            )}
                            {activeTypes.includes('issues') && (
                                <ResultSection
                                    type="issues"
                                    result={results?.issues ?? null}
                                    renderer={(item) => <IssueItem item={item} />}
                                />
                            )}
                            {activeTypes.includes('users') && (
                                <ResultSection
                                    type="users"
                                    result={results?.users ?? null}
                                    renderer={(item) => <UserItem item={item} />}
                                />
                            )}
                            {activeTypes.includes('messages') && (
                                <>
                                    {messagesLoading && (
                                        <div className="flex items-center justify-center py-8">
                                            <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
                                        </div>
                                    )}
                                    {!messagesLoading && messagesData && messagesData.messages.length > 0 && (
                                        <Card>
                                            <CardHeader className="pb-3">
                                                <CardTitle className="flex items-center gap-2 text-sm">
                                                    <MessageSquare className="h-4 w-4" />
                                                    Messages
                                                    <Badge variant="secondary" className="ml-auto text-xs">
                                                        {messagesData.total}
                                                    </Badge>
                                                </CardTitle>
                                                {useRoomScoped ? (
                                                    <p className="text-xs text-muted-foreground -mt-1">
                                                        in room <span className="font-mono font-medium">{roomIdInput}</span>
                                                    </p>
                                                ) : (
                                                    <p className="text-xs text-muted-foreground -mt-1">
                                                        across all accessible rooms
                                                    </p>
                                                )}
                                            </CardHeader>
                                            <CardContent className="divide-y">
                                                {messagesData.messages.map((msg) => (
                                                    <MessageItem key={msg.id} item={msg} />
                                                ))}
                                            </CardContent>
                                        </Card>
                                    )}
                                    {!messagesLoading && messagesData && messagesData.messages.length === 0 && (
                                        <Card>
                                            <CardHeader className="pb-3">
                                                <CardTitle className="flex items-center gap-2 text-sm">
                                                    <MessageSquare className="h-4 w-4" />
                                                    Messages
                                                </CardTitle>
                                            </CardHeader>
                                            <CardContent>
                                                <p className="text-sm text-muted-foreground text-center py-4">
                                                    {useRoomScoped
                                                        ? `No messages found in room "${roomIdInput}" matching "${q}"`
                                                        : `No messages found matching "${q}" across accessible rooms`}
                                                </p>
                                            </CardContent>
                                        </Card>
                                    )}
                                </>
                            )}
                        </div>

                        {getTotal(results) === 0 && (
                            <div className="text-center py-16">
                                <Search className="h-10 w-10 mx-auto mb-3 text-muted-foreground/20" />
                                <p className="font-medium">No results found</p>
                                <p className="text-sm text-muted-foreground mt-1">
                                    Try different keywords or check your spelling.
                                </p>
                            </div>
                        )}
                    </>
                )}
            </div>
        </div>
    );
}
