import { useHistory, useLocation } from '@docusaurus/router';
import searchConfig from '@docuservix-search/config';
import Link from '@docusaurus/Link';
import Layout from '@theme/Layout';
import React, { useCallback, useEffect, useRef, useState } from 'react';

import type { SearchResult } from '../../types';

import styles from './styles.module.css';

const MAX_RESULTS = 25;

function useQuery(): string {
    const location = useLocation();
    const params = new URLSearchParams(location.search);

    return params.get('q') ?? '';
}

export default function SearchPage(): JSX.Element {
    const urlQuery = useQuery();
    const history = useHistory();

    const [inputValue, setInputValue] = useState(urlQuery);
    const [results, setResults] = useState<SearchResult[]>([]);
    const [notices, setNotices] = useState<string[]>([]);
    const [errors, setErrors] = useState<string[]>([]);
    const [loading, setLoading] = useState(false);
    const [activeFilter, setActiveFilter] = useState<string>('all');

    const abortRef = useRef<AbortController | null>(null);

    const runSearch = useCallback(async (q: string) => {
        if (!q.trim()) {
            setResults([]);
            setNotices([]);
            setErrors([]);

            return;
        }

        if (abortRef.current) {
            abortRef.current.abort();
        }

        const controller = new AbortController();

        abortRef.current = controller;

        const timeout = searchConfig.timeout ?? 5000;
        const timeoutId = setTimeout(() => controller.abort(), timeout);

        setLoading(true);
        setErrors([]);

        try {
            const settled = await Promise.allSettled(
                searchConfig.providers.map((provider) => provider.search(q, controller.signal)),
            );

            if (controller.signal.aborted) {
                return;
            }

            const allResults: SearchResult[] = [];
            const allNotices: string[] = [];
            const allErrors: string[] = [];

            for (let i = 0; i < settled.length; i++) {
                const outcome = settled[i];
                const provider = searchConfig.providers[i];

                if (outcome.status === 'fulfilled') {
                    allResults.push(...outcome.value.results);

                    if (outcome.value.notice) {
                        allNotices.push(outcome.value.notice);
                    }
                } else {
                    allErrors.push(`${provider.name}: недоступен`);
                }
            }

            allResults.sort((a, b) => b.relevance - a.relevance);

            setResults(allResults.slice(0, MAX_RESULTS));
            setNotices(allNotices);
            setErrors(allErrors);
            setActiveFilter('all');
        } finally {
            clearTimeout(timeoutId);
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        setInputValue(urlQuery);
        runSearch(urlQuery);
    }, [urlQuery, runSearch]);

    useEffect(() => {
        return () => {
            if (abortRef.current) {
                abortRef.current.abort();
            }
        };
    }, []);

    const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setInputValue(e.target.value);
    };

    const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
        if (e.key === 'Enter' && inputValue.trim()) {
            history.push(`/search?q=${encodeURIComponent(inputValue.trim())}`);
        }
    };

    const sourceTypes = ['all', ...Array.from(new Set(results.map((r) => r.type)))];

    const filteredResults =
        activeFilter === 'all' ? results : results.filter((r) => r.type === activeFilter);

    const typeLabel: Record<string, string> = {
        all: 'Все',
        docs: 'Docs',
    };

    return (
        <Layout title={urlQuery ? `Поиск: ${urlQuery}` : 'Поиск'}>
            <div className={styles.container}>
                <h1 className={styles.heading}>Поиск</h1>
                <input
                    className={styles.searchInput}
                    type="search"
                    value={inputValue}
                    onChange={handleInputChange}
                    onKeyDown={handleInputKeyDown}
                    placeholder="Введите запрос и нажмите Enter..."
                    aria-label="Поисковый запрос"
                />

                {urlQuery && (
                    <Link
                        to={`/chat?q=${encodeURIComponent(urlQuery)}`}
                        className={styles.chatLink}
                    >
                        Спросить ИИ →
                    </Link>
                )}

                {errors.length > 0 && (
                    <div
                        className="alert alert--warning"
                        role="alert"
                    >
                        {errors.map((err, i) => (
                            <div key={i}>{err}</div>
                        ))}
                    </div>
                )}

                {notices.length > 0 && (
                    <div
                        className="alert alert--info"
                        role="note"
                    >
                        {notices.map((notice, i) => (
                            <div key={i}>{notice}</div>
                        ))}
                    </div>
                )}

                {loading && <div className={styles.loadingText}>Поиск...</div>}

                {!loading && urlQuery && (
                    <>
                        {sourceTypes.length > 2 && (
                            <div
                                className={styles.filters}
                                role="tablist"
                            >
                                {sourceTypes.map((type) => (
                                    <button
                                        key={type}
                                        role="tab"
                                        aria-selected={activeFilter === type}
                                        className={
                                            activeFilter === type
                                                ? `${styles.filterBtn} ${styles.filterBtnActive}`
                                                : styles.filterBtn
                                        }
                                        onClick={() => setActiveFilter(type)}
                                    >
                                        {typeLabel[type] ?? type}
                                    </button>
                                ))}
                            </div>
                        )}

                        {filteredResults.length === 0 ? (
                            <div className={styles.empty}>Ничего не найдено</div>
                        ) : (
                            <div className={styles.resultList}>
                                {filteredResults.map((result, i) => (
                                    <a
                                        key={`${result.url}-${i}`}
                                        href={result.url}
                                        className={styles.resultItem}
                                    >
                                        <div className={styles.resultTitle}>{result.title}</div>
                                        <div className={styles.resultMeta}>
                                            <span
                                                className={styles.badge}
                                                data-type={result.type}
                                            >
                                                {typeLabel[result.type] ?? result.type}
                                            </span>
                                            <span className={styles.resultPath}>{result.path}</span>
                                            {result.anchor && (
                                                <span className={styles.resultAnchor}>
                                                    #{result.anchor}
                                                </span>
                                            )}
                                            <span className={styles.resultScore}>
                                                {Math.round(result.relevance * 100)}%
                                            </span>
                                        </div>
                                        {result.content && (
                                            <div className={styles.resultContent}>
                                                {result.content}
                                            </div>
                                        )}
                                    </a>
                                ))}
                            </div>
                        )}
                    </>
                )}
            </div>
        </Layout>
    );
}
