import { useMemo, useRef } from "preact/hooks";

import { useQuery } from "@common/hooks/useAsyncState";
import { useInputState } from "@common/hooks/useInputState";
import { useUpdate } from "@common/hooks/useUpdate";

import { useAppState } from "../contexts/state";
import LLM from "../utils/llm";
import styles from "../assets/settings-modal.module.css";
import { X } from "lucide-preact";

interface Props {
    onClose: () => void;
}

export const ConnectionSettingsModal = ({ onClose }: Props) => {
    const { connection, model, dispatch } = useAppState();
    const [url, setUrl] = useInputState(connection?.url ?? "");
    const [apiKey, setApiKey] = useInputState(connection?.apiKey ?? "");
    const [selectedModel, setSelectedModel] = useInputState(model?.id ?? "");
    const [update, triggerFetch] = useUpdate();

    const urlRef = useRef(url);
    const apiKeyRef = useRef(apiKey);

    urlRef.current = url;
    apiKeyRef.current = apiKey;

    const connectionToFetch = useMemo<LLM.Connection | null>(() => {
        const currentUrl = urlRef.current;
        const currentApiKey = apiKeyRef.current;
        if (!currentUrl || !currentApiKey) return null;
        return { url: currentUrl, apiKey: currentApiKey };
    }, [update]);

    const fetchModels = useMemo(() => async (conn: LLM.Connection | null) => {
        if (!conn) return [];
        const r = await LLM.getModels(conn);
        return r.data;
    }, []);

    const modelsData = useQuery(fetchModels, connectionToFetch);

    const isLoadingModels = connectionToFetch != null && modelsData == undefined;
    const groupedModels = useMemo(() => {
        const sorted = (modelsData ?? []).sort((a, b) => {
            const aWeight = Number(a.support_tools) * 2 + Number(a.support_thinking);
            const bWeight = Number(b.support_tools) * 2 + Number(b.support_thinking);
            if (aWeight !== bWeight) {
                return bWeight - aWeight;
            }

            const aContext = a.max_context ?? 0;
            const bContext = b.max_context ?? 0;
            if (aContext !== bContext) {
                return bContext - aContext;
            }

            return a.id.localeCompare(b.id);
        });

        // Group by context size
        const groups = Map.groupBy(sorted, m => m.max_context ?? 0);

        // Convert to array sorted by context size (bigger first)
        return Array.from(groups.entries())
            .sort((a, b) => b[0] - a[0])
            .map(([context, models]) => ({ context, models }));
    }, [modelsData]);

    const handleBlur = () => {
        if (url && apiKey) {
            triggerFetch();
        }
    };

    const handleKeyDown = (e: KeyboardEvent) => {
        if (e.key === 'Enter' && url && apiKey) {
            triggerFetch();
        }
    };

    const handleConfirm = () => {
        dispatch({
            type: 'SET_CONNECTION',
            connection: connectionToFetch,
        });
        const selectedModelInfo = modelsData?.find(m => m.id === selectedModel) ?? null;
        dispatch({
            type: 'SET_MODEL',
            model: selectedModelInfo,
        });
        onClose();
    };

    const connectionToTest = url && apiKey ? { url, apiKey } : null;

    return (
        <div class={styles.overlay} onClick={onClose}>
            <div class={styles.modal} onClick={(e) => e.stopPropagation()}>
                <div class={styles.header}>
                    <h2 class={styles.title}>Connection Settings</h2>
                    <button class={styles.closeButton} onClick={onClose}>
                        <X size={20} />
                    </button>
                </div>
                <div class={styles.content}>
                    <div class={styles.form} autocomplete="off">
                        <div class={styles.formGroup}>
                            <label class={styles.label}>
                                API URL
                            </label>
                            <input
                                type="text"
                                value={url}
                                onInput={setUrl}
                                onBlur={handleBlur}
                                onKeyDown={handleKeyDown}
                                placeholder="http://localhost:1234"
                                class={styles.input}
                                autocomplete="off"
                                name="api-url-random"
                            />
                        </div>
                        <div class={styles.formGroup}>
                            <label class={styles.label}>
                                API Key
                            </label>
                            <input
                                type="password"
                                value={apiKey}
                                onInput={setApiKey}
                                onBlur={handleBlur}
                                onKeyDown={handleKeyDown}
                                placeholder="your-api-key"
                                class={styles.input}
                                autocomplete="new-password"
                                name="api-key-random"
                            />
                        </div>
                        <div class={styles.formGroup}>
                            <label class={styles.label}>
                                Model
                            </label>
                            {connectionToTest ? (
                                isLoadingModels ? (
                                    <p>Loading models...</p>
                                ) : groupedModels.length > 0 ? (
                                    <select
                                        value={selectedModel}
                                        onChange={setSelectedModel}
                                        class={styles.select}
                                    >
                                        <option value="">Select a model</option>
                                        {groupedModels.map(({ context, models }) => (
                                            <optgroup key={context} label={`${context} context`}>
                                                {models.map(m => (
                                                    <option key={m.id} value={m.id}>
                                                        {m.support_tools ? '🔨' : ''}{m.support_thinking ? '🧠' : ''}{m.id} {m.max_length ? `(len: ${m.max_length})` : ''}
                                                    </option>
                                                ))}
                                            </optgroup>
                                        ))}
                                    </select>
                                ) : (
                                    <p>No models available</p>
                                )
                            ) : (
                                <p>Enter connection details to load models</p>
                            )}
                        </div>
                    </div>
                </div>
                <div class={styles.footer}>
                    <button onClick={onClose} class={`${styles.button} ${styles.buttonSecondary}`}>
                        Cancel
                    </button>
                    <button onClick={handleConfirm} class={`${styles.button} ${styles.buttonPrimary}`}>
                        Confirm
                    </button>
                </div>
            </div>
        </div>
    );
};
