import { ChevronDown, Eye, EyeOff, KeyRound, Save, Trash2 } from 'lucide-react';
import type { FormEvent } from 'react';
import { useRef, useState } from 'react';
import { toast } from 'sonner';

import { ConfigError, Field } from '@/components/admin/admin-form-parts';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { Spinner } from '@/components/ui/spinner';
import { stringValue } from '@/lib/admin';
import { cn } from '@/lib/utils';
import { patchLlmConfig } from '@/lib/rag-client';
import type { LlmConfig, LlmForm } from '@/types/admin';

type ApiKeyMode = 'configured' | 'editing' | 'clearing';

const REASONING_EFFORT_OPTIONS: Record<string, string[]> = {
    deepseek: ['high', 'max'],
    openai: ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'],
};

function SearchableSelect({
    disabled = false,
    onChange,
    options,
    placeholder = 'Pilih...',
    searchPlaceholder = 'Cari...',
    value,
}: {
    disabled?: boolean;
    onChange: (value: string) => void;
    options: string[];
    placeholder?: string;
    searchPlaceholder?: string;
    value: string;
}) {
    const [open, setOpen] = useState(false);
    const [query, setQuery] = useState('');
    const containerRef = useRef<HTMLDivElement>(null);

    const filtered = options.filter((o) =>
        o.toLowerCase().includes(query.toLowerCase()),
    );

    return (
        <div className="relative" ref={containerRef}>
            <button
                className={cn(
                    'flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background',
                    'focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-none',
                    disabled && 'cursor-not-allowed opacity-50',
                )}
                disabled={disabled}
                type="button"
                onClick={() => {
                    setOpen((v) => !v);
                    setQuery('');
                }}
            >
                <span className={value ? '' : 'text-muted-foreground'}>
                    {value || placeholder}
                </span>
                <ChevronDown className="size-4 shrink-0 opacity-50" />
            </button>

            {open && (
                <div
                    className="absolute z-50 mt-1 w-full rounded-md border bg-popover text-popover-foreground shadow-md"
                    onMouseDown={(e) => e.stopPropagation()}
                >
                    <div className="border-b p-1">
                        <Input
                            autoFocus
                            className="h-8 text-sm"
                            placeholder={searchPlaceholder}
                            value={query}
                            onChange={(e) => setQuery(e.target.value)}
                            onBlur={() => {
                                setTimeout(() => setOpen(false), 150);
                            }}
                        />
                    </div>
                    <div className="max-h-52 overflow-y-auto p-1">
                        {filtered.length > 0 ? (
                            filtered.map((option) => (
                                <button
                                    key={option}
                                    className={cn(
                                        'flex w-full items-center rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground',
                                        value === option &&
                                            'bg-accent text-accent-foreground',
                                    )}
                                    type="button"
                                    onClick={() => {
                                        onChange(option);
                                        setOpen(false);
                                        setQuery('');
                                    }}
                                >
                                    {option}
                                </button>
                            ))
                        ) : (
                            <p className="py-6 text-center text-sm text-muted-foreground">
                                Tidak ditemukan.
                            </p>
                        )}
                    </div>
                </div>
            )}
        </div>
    );
}

function CreatableBaseUrlSelect({
    onChange,
    options,
    value,
}: {
    onChange: (value: string) => void;
    options: string[];
    value: string;
}) {
    const [customMode, setCustomMode] = useState(
        value !== '' && !options.includes(value),
    );

    const selectValue = customMode
        ? '__custom__'
        : options.includes(value)
          ? value
          : '';

    return (
        <div className="grid gap-2">
            <Select
                value={selectValue}
                onValueChange={(val) => {
                    if (val === '__custom__') {
                        setCustomMode(true);
                        if (options.includes(value)) onChange('');
                    } else {
                        setCustomMode(false);
                        onChange(val);
                    }
                }}
            >
                <SelectTrigger className="w-full">
                    <SelectValue placeholder="Pilih atau masukkan custom URL" />
                </SelectTrigger>
                <SelectContent>
                    {options.map((url) => (
                        <SelectItem key={url} value={url}>
                            {url}
                        </SelectItem>
                    ))}
                    <SelectItem value="__custom__">Custom URL...</SelectItem>
                </SelectContent>
            </Select>
            {customMode && (
                <Input
                    placeholder="https://custom-gateway.com/v1"
                    value={value}
                    onChange={(e) => onChange(e.target.value)}
                />
            )}
        </div>
    );
}

function ApiKeyInput({
    mode,
    onModeChange,
    onChange,
    value,
}: {
    mode: ApiKeyMode;
    onModeChange: (mode: ApiKeyMode) => void;
    onChange: (value: string) => void;
    value: string;
}) {
    const [show, setShow] = useState(false);

    if (mode === 'configured') {
        return (
            <div className="flex items-center gap-2">
                <div className="flex h-9 flex-1 items-center gap-2 rounded-md border border-input bg-muted/50 px-3 text-sm text-muted-foreground">
                    <KeyRound className="size-3.5 shrink-0" />
                    <span>API key tersimpan</span>
                </div>
                <Button
                    size="sm"
                    type="button"
                    variant="outline"
                    onClick={() => onModeChange('editing')}
                >
                    Ubah
                </Button>
                <Button
                    className="text-destructive hover:text-destructive"
                    size="sm"
                    type="button"
                    variant="outline"
                    onClick={() => onModeChange('clearing')}
                >
                    <Trash2 className="size-3.5" />
                </Button>
            </div>
        );
    }

    if (mode === 'clearing') {
        return (
            <div className="flex items-center gap-2">
                <div className="flex h-9 flex-1 items-center gap-2 rounded-md border border-destructive/50 bg-destructive/5 px-3 text-sm text-destructive">
                    <Trash2 className="size-3.5 shrink-0" />
                    <span>API key akan dihapus</span>
                </div>
                <Button
                    size="sm"
                    type="button"
                    variant="outline"
                    onClick={() => onModeChange('configured')}
                >
                    Batal
                </Button>
            </div>
        );
    }

    return (
        <div className="relative">
            <Input
                autoComplete="off"
                autoFocus
                className="pr-10"
                placeholder="sk-..."
                type={show ? 'text' : 'password'}
                value={value}
                onChange={(e) => onChange(e.target.value)}
            />
            <button
                className="absolute top-1/2 right-3 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                type="button"
                onClick={() => setShow((v) => !v)}
            >
                {show ? (
                    <EyeOff className="size-4" />
                ) : (
                    <Eye className="size-4" />
                )}
            </button>
        </div>
    );
}

export function AdminLlmForm({ llm }: { llm?: LlmConfig | null }) {
    const cfg = llm ?? {};
    const providers = cfg.providers ?? {};
    const systemPromptsMap = cfg.system_prompts ?? {};
    const systemPromptKeys = Object.keys(systemPromptsMap);
    const initialSystemPromptKey = systemPromptKeys[0] ?? 'default';
    const initialProviderInfo = providers[cfg.active_provider ?? ''];

    const [formData, setFormData] = useState<LlmForm>({
        active_model: stringValue(cfg.active_model),
        active_provider: stringValue(cfg.active_provider),
        api_key: stringValue(cfg.api_key),
        base_url: stringValue(initialProviderInfo?.base_url),
        max_tokens: stringValue(cfg.max_tokens),
        reasoning_effort: stringValue(cfg.reasoning_effort),
        request_timeout: stringValue(cfg.request_timeout),
        system_prompt: systemPromptsMap[initialSystemPromptKey] ?? '',
        temperature: stringValue(cfg.temperature),
    });
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [error, setError] = useState<string | undefined>();
    const [selectedTemplate, setSelectedTemplate] = useState<string>(
        initialSystemPromptKey,
    );
    const [apiKeyMode, setApiKeyMode] = useState<ApiKeyMode>(
        cfg.api_key_set ? 'configured' : 'editing',
    );

    function setField<K extends keyof LlmForm>(
        key: K,
        value: LlmForm[K],
    ): void {
        setFormData((prev) => ({ ...prev, [key]: value }));
    }

    function handleProviderChange(provider: string): void {
        const config = providers[provider];
        setFormData((prev) => ({
            ...prev,
            active_provider: provider,
            active_model: '',
            reasoning_effort: '',
            base_url: config?.base_url ?? '',
        }));
    }

    async function handleSubmit(
        event: FormEvent<HTMLFormElement>,
    ): Promise<void> {
        event.preventDefault();
        setIsSubmitting(true);
        setError(undefined);

        try {
            const payload: Record<string, unknown> = {};

            if (formData.active_provider) {
                payload.active_provider = formData.active_provider;
                payload.providers = {
                    [formData.active_provider]: {
                        base_url: formData.base_url || null,
                    },
                };
            }

            if (formData.active_model)
                payload.active_model = formData.active_model;
            if (apiKeyMode === 'clearing') {
                payload.api_key = null;
            } else if (apiKeyMode === 'editing' && formData.api_key) {
                payload.api_key = formData.api_key;
            }
            payload.reasoning_effort = formData.reasoning_effort || null;
            if (formData.max_tokens)
                payload.max_tokens = parseInt(formData.max_tokens, 10);
            if (formData.request_timeout)
                payload.request_timeout = parseInt(
                    formData.request_timeout,
                    10,
                );
            if (formData.temperature)
                payload.temperature = parseFloat(formData.temperature);
            if (formData.system_prompt) {
                payload.system_prompts = {
                    [selectedTemplate]: formData.system_prompt,
                };
            }

            const result = await patchLlmConfig(payload);

            const savedProviders = result.providers ?? {};
            const savedSystemPrompts = result.system_prompts ?? {};
            const savedKey =
                savedSystemPrompts[selectedTemplate] !== undefined
                    ? selectedTemplate
                    : (Object.keys(savedSystemPrompts)[0] ?? selectedTemplate);

            setSelectedTemplate(savedKey);

            const savedProviderInfo =
                savedProviders[result.active_provider ?? ''];
            setFormData({
                active_model: stringValue(result.active_model),
                active_provider: stringValue(result.active_provider),
                api_key: '',
                base_url: stringValue(savedProviderInfo?.base_url),
                max_tokens: stringValue(result.max_tokens),
                reasoning_effort: stringValue(result.reasoning_effort),
                request_timeout: stringValue(result.request_timeout),
                system_prompt: savedSystemPrompts[savedKey] ?? '',
                temperature: stringValue(result.temperature),
            });

            setApiKeyMode(result.api_key_set ? 'configured' : 'editing');
            toast.success('Konfigurasi LLM berhasil disimpan');
        } catch (e) {
            setError(
                e instanceof Error
                    ? e.message
                    : 'Gagal menyimpan konfigurasi LLM.',
            );
        } finally {
            setIsSubmitting(false);
        }
    }

    const providerConfig = providers[formData.active_provider];
    const reasoningEffortOptions =
        REASONING_EFFORT_OPTIONS[formData.active_provider] ?? [];
    const baseUrlOptions = providerConfig?.base_url
        ? [providerConfig.base_url]
        : [];

    return (
        <form
            className="grid gap-4"
            onSubmit={(e) => {
                void handleSubmit(e);
            }}
        >
            <ConfigError message={error} />

            {/* Model */}
            <Card className="border-(--lecturer-border) bg-(--lecturer-surface)">
                <CardContent className="px-6">
                    <div className="grid gap-3">
                        <h3 className="text-base font-semibold text-(--lecturer-text)">
                            Model
                        </h3>
                        <div className="grid gap-3 md:grid-cols-2">
                            <Field
                                current={llm?.active_provider}
                                hint="Penyedia layanan AI yang digunakan untuk menjawab pertanyaan."
                                label="Provider"
                            >
                                <Select
                                    value={formData.active_provider}
                                    onValueChange={handleProviderChange}
                                >
                                    <SelectTrigger className="w-full">
                                        <SelectValue placeholder="Pilih provider" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {Object.keys(providers).map((p) => (
                                            <SelectItem key={p} value={p}>
                                                {p.charAt(0).toUpperCase() +
                                                    p.slice(1)}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            </Field>

                            <Field
                                current={llm?.active_model}
                                hint="Model AI yang digunakan. Pilih provider terlebih dahulu."
                                label="Model"
                            >
                                <SearchableSelect
                                    disabled={!formData.active_provider}
                                    options={
                                        providerConfig?.model_options ?? []
                                    }
                                    placeholder={
                                        formData.active_provider
                                            ? 'Pilih model'
                                            : 'Pilih provider dulu'
                                    }
                                    searchPlaceholder="Cari model..."
                                    value={formData.active_model}
                                    onChange={(v) =>
                                        setField('active_model', v)
                                    }
                                />
                            </Field>

                            <div className="md:col-span-2">
                                <Field
                                    hint="URL endpoint API provider. Pilih dari daftar atau masukkan custom URL."
                                    label="Base URL"
                                >
                                    <CreatableBaseUrlSelect
                                        key={formData.active_provider}
                                        options={baseUrlOptions}
                                        value={formData.base_url}
                                        onChange={(v) =>
                                            setField('base_url', v)
                                        }
                                    />
                                </Field>
                            </div>
                        </div>
                    </div>
                </CardContent>
            </Card>

            {/* Parameter */}
            <Card className="border-(--lecturer-border) bg-(--lecturer-surface)">
                <CardContent className="px-6">
                    <div className="grid gap-3">
                        <h3 className="text-base font-semibold text-(--lecturer-text)">
                            Parameter
                        </h3>
                        <div className="grid gap-3 md:grid-cols-2">
                            <Field
                                hint="Tingkat kreativitas jawaban (0–1). Rendah = konsisten, tinggi = lebih variatif."
                                label="Temperature"
                            >
                                <Input
                                    min="0"
                                    step="0.01"
                                    type="number"
                                    value={formData.temperature}
                                    onChange={(event) =>
                                        setField(
                                            'temperature',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <Field
                                hint="Batas maksimum token yang dihasilkan per respons."
                                label="Max Tokens"
                            >
                                <Input
                                    min="1"
                                    type="number"
                                    value={formData.max_tokens}
                                    onChange={(event) =>
                                        setField(
                                            'max_tokens',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <Field
                                hint="Batas waktu menunggu respons dari API dalam detik."
                                label="Request Timeout"
                            >
                                <Input
                                    min="1"
                                    type="number"
                                    value={formData.request_timeout}
                                    onChange={(event) =>
                                        setField(
                                            'request_timeout',
                                            event.target.value,
                                        )
                                    }
                                />
                            </Field>

                            <Field
                                hint="Tingkat usaha reasoning model. Tersedia sesuai provider yang dipilih."
                                label="Reasoning Effort"
                            >
                                <Select
                                    disabled={!formData.active_provider}
                                    value={
                                        formData.reasoning_effort || '__none__'
                                    }
                                    onValueChange={(val) =>
                                        setField(
                                            'reasoning_effort',
                                            val === '__none__' ? '' : val,
                                        )
                                    }
                                >
                                    <SelectTrigger className="w-full">
                                        <SelectValue placeholder="Tidak diatur" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        <SelectItem value="__none__">
                                            Tidak diatur
                                        </SelectItem>
                                        {reasoningEffortOptions.map(
                                            (effort) => (
                                                <SelectItem
                                                    key={effort}
                                                    value={effort}
                                                >
                                                    {effort}
                                                </SelectItem>
                                            ),
                                        )}
                                    </SelectContent>
                                </Select>
                            </Field>
                        </div>
                    </div>
                </CardContent>
            </Card>

            {/* Autentikasi */}
            <Card className="border-(--lecturer-border) bg-(--lecturer-surface)">
                <CardContent className="px-6">
                    <div className="grid gap-3">
                        <h3 className="text-base font-semibold text-(--lecturer-text)">
                            Autentikasi
                        </h3>
                        <Field
                            hint="API key untuk autentikasi ke provider. Nilai disimpan terenkripsi."
                            label="API Key"
                        >
                            <ApiKeyInput
                                mode={apiKeyMode}
                                value={formData.api_key}
                                onChange={(v) => setField('api_key', v)}
                                onModeChange={setApiKeyMode}
                            />
                        </Field>
                    </div>
                </CardContent>
            </Card>

            {/* System Prompt */}
            <Card className="border-(--lecturer-border) bg-(--lecturer-surface)">
                <CardContent className="px-6">
                    <div className="grid gap-3">
                        <h3 className="text-base font-semibold text-(--lecturer-text)">
                            System Prompt
                        </h3>
                        <Field
                            hint="Pilih key system prompt yang ingin diedit. Setiap key menyimpan instruksi berbeda."
                            label="Template"
                        >
                            <Select
                                disabled={systemPromptKeys.length === 0}
                                value={selectedTemplate}
                                onValueChange={(key) => {
                                    setSelectedTemplate(key);
                                    setField(
                                        'system_prompt',
                                        systemPromptsMap[key] ?? '',
                                    );
                                }}
                            >
                                <SelectTrigger className="w-full">
                                    <SelectValue placeholder="Pilih key..." />
                                </SelectTrigger>
                                <SelectContent>
                                    {systemPromptKeys.map((key) => (
                                        <SelectItem key={key} value={key}>
                                            {key}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                        </Field>

                        <Field
                            hint="Instruksi awal yang selalu dikirim ke model sebelum percakapan dimulai."
                            label="Prompt"
                        >
                            <textarea
                                className="min-h-36 w-full rounded-md border border-input px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
                                value={formData.system_prompt}
                                onChange={(event) => {
                                    setField(
                                        'system_prompt',
                                        event.target.value,
                                    );
                                }}
                            />
                        </Field>
                    </div>
                </CardContent>
            </Card>

            <div className="flex justify-end">
                <Button disabled={isSubmitting} type="submit">
                    {isSubmitting ? (
                        <Spinner className="size-4" />
                    ) : (
                        <Save className="size-4" />
                    )}
                    Simpan LLM
                </Button>
            </div>
        </form>
    );
}
