"use client";

import {useEffect, useMemo, useState} from "react";
import Link from "next/link";
import {toast} from "sonner";
import {
    Eye,
    Gamepad2,
    Mic2,
    Pencil,
    Play,
    Plus,
    RefreshCw,
    Save,
    School,
    Search,
    Settings2,
    SlidersHorizontal,
    Trash2,
} from "lucide-react";
import {Badge} from "@/components/ui/badge";
import {Button} from "@/components/ui/button";
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card";
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from "@/components/ui/dialog";
import {Input} from "@/components/ui/input";
import {Switch} from "@/components/ui/switch";
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";

type Grade = "小班" | "中班" | "大班";

type ClassType = {
    id: number;
    name: string;
    enabled: boolean;
};

type WordRecord = {
    id: number;
    grade: Grade;
    classTypeId: number;
    classTypeName: string;
    english: string;
    chinese: string;
    image: string;
    audio: string;
    enabled: boolean;
};

type WordForm = {
    id?: number;
    grade: Grade;
    classTypeId: number;
    english: string;
    chinese: string;
    image: string;
    audio?: string;
    enabled: boolean;
};

type AppSettings = {
  ttsVoice: string;
  ttsRate: string;
  scorePerCorrect: number;
  scorePerWrong: number;
  autoSpeak: boolean;
  wordDisplayMode: "uppercase" | "capitalize" | "input";
  pkWordCount: number;
  pkOptionCount: number;
};

type BatchAudioProgress = {
    running: boolean;
    total: number;
    done: number;
    success: number;
    failed: number;
    current: string;
};

type SettingsSection = "voice" | "rules" | "classTypes" | "preview";

const grades: Grade[] = ["小班", "中班", "大班"];
const defaultSettings: AppSettings = {
  ttsVoice: "en-US-EmmaMultilingualNeural",
  ttsRate: "-10%",
  scorePerCorrect: 10,
  scorePerWrong: 0,
  autoSpeak: true,
  wordDisplayMode: "uppercase",
  pkWordCount: 0,
  pkOptionCount: 4,
};

const ttsVoiceOptions = [
    {value: "en-US-EmmaMultilingualNeural", label: "Emma - 美式英语 女声"},
    {value: "en-US-JennyNeural", label: "Jenny - 美式英语 女声"},
    {value: "en-US-GuyNeural", label: "Guy - 美式英语 男声"},
    {value: "en-GB-SoniaNeural", label: "Sonia - 英式英语 女声"},
    {value: "en-GB-RyanNeural", label: "Ryan - 英式英语 男声"},
    {value: "en-AU-NatashaNeural", label: "Natasha - 澳洲英语 女声"},
    {value: "en-AU-WilliamNeural", label: "William - 澳洲英语 男声"},
];

const ttsRateOptions = [
    {value: "-30%", label: "较慢 (-30%)"},
    {value: "-20%", label: "慢速 (-20%)"},
    {value: "-10%", label: "稍慢 (-10%)"},
    {value: "+0%", label: "正常"},
    {value: "+10%", label: "稍快 (+10%)"},
];

const wordDisplayModeOptions: Array<{ value: AppSettings["wordDisplayMode"]; label: string }> = [
  { value: "uppercase", label: "全部大写：APPLE" },
  { value: "capitalize", label: "首字母大写：Apple" },
  { value: "input", label: "按输入显示：apple / Apple" },
];

const settingsSections: Array<{ id: SettingsSection; label: string; description: string; icon: typeof Mic2 }> = [
    {id: "voice", label: "语音设置", description: "Edge TTS 声音与语速", icon: Mic2},
    {id: "rules", label: "课堂规则", description: "得分与自动朗读", icon: SlidersHorizontal},
    {id: "classTypes", label: "班级类型", description: "定制 PK 入口班型", icon: School},
    {id: "preview", label: "页面预览", description: "打开课堂展示页", icon: Eye},
];

function createEmptyWordForm(classTypeId = 0): WordForm {
    return {
        grade: "中班",
        classTypeId,
        english: "",
        chinese: "",
        image: "",
        audio: "",
        enabled: true,
    };
}

export default function AdminPage() {
    const [wordList, setWordList] = useState<WordRecord[]>([]);
    const [classTypes, setClassTypes] = useState<ClassType[]>([]);
    const [settings, setSettings] = useState<AppSettings>(defaultSettings);
    const [query, setQuery] = useState("");
    const [gradeFilter, setGradeFilter] = useState<"all" | Grade>("all");
    const [classTypeFilter, setClassTypeFilter] = useState<"all" | number>("all");
    const [wordForm, setWordForm] = useState<WordForm>(createEmptyWordForm());
    const [wordDialogOpen, setWordDialogOpen] = useState(false);
    const [settingsDialogOpen, setSettingsDialogOpen] = useState(false);
    const [settingsSection, setSettingsSection] = useState<SettingsSection>("voice");
    const [classTypeName, setClassTypeName] = useState("");
    const [editingClassType, setEditingClassType] = useState<ClassType | null>(null);
    const [loading, setLoading] = useState(true);
    const [batchAudioProgress, setBatchAudioProgress] = useState<BatchAudioProgress>({
        running: false,
        total: 0,
        done: 0,
        success: 0,
        failed: 0,
        current: "",
    });

    useEffect(() => {
        void loadData();
    }, []);

    async function loadData() {
        setLoading(true);
        const [wordsResponse, classTypesResponse, settingsResponse] = await Promise.all([
            fetch("/api/words", {cache: "no-store"}),
            fetch("/api/class-types", {cache: "no-store"}),
            fetch("/api/settings", {cache: "no-store"}),
        ]);
        const wordsData = (await wordsResponse.json()) as { words: WordRecord[] };
        const classTypesData = (await classTypesResponse.json()) as { classTypes: ClassType[] };
        const settingsData = (await settingsResponse.json()) as { settings: Partial<AppSettings> };
        setWordList(wordsData.words);
        setClassTypes(classTypesData.classTypes);
        setSettings(mergeSettings(settingsData.settings));
        setWordForm((form) => ({
            ...form,
            classTypeId: form.classTypeId || classTypesData.classTypes[0]?.id || 0,
        }));
        setLoading(false);
    }

    const enabledCount = wordList.filter((word) => word.enabled).length;
    const audioCount = wordList.filter((word) => word.audio).length;
    const filteredWords = useMemo(() => {
        return wordList.filter((word) => {
            const matchQuery = word.english.toLowerCase().includes(query.toLowerCase());
            const matchGrade = gradeFilter === "all" || word.grade === gradeFilter;
            const matchClassType = classTypeFilter === "all" || word.classTypeId === classTypeFilter;
            return matchQuery && matchGrade && matchClassType;
        });
    }, [wordList, query, gradeFilter, classTypeFilter]);

    function openCreateWordDialog() {
        setWordForm(createEmptyWordForm(classTypes[0]?.id || 0));
        setWordDialogOpen(true);
    }

    function openEditWordDialog(word: WordRecord) {
        setWordForm({
            id: word.id,
            grade: word.grade,
            classTypeId: word.classTypeId,
            english: word.english,
            chinese: word.chinese,
            image: word.image,
            audio: word.audio,
            enabled: word.enabled,
        });
        setWordDialogOpen(true);
    }

    async function saveWord() {
        if (!wordForm.english.trim()) {
            toast.error("题库英语不能为空");
            return null;
        }

        if (!wordForm.classTypeId) {
            toast.error("请先创建班级类型");
            return null;
        }

        const response = await fetch(wordForm.id ? `/api/words/${wordForm.id}` : "/api/words", {
            method: wordForm.id ? "PUT" : "POST",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify(wordForm),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "保存题库失败");
            return null;
        }

        toast.success(wordForm.id ? "题库已更新，语音需要重新生成" : "题库已添加");
        setWordDialogOpen(false);
        await loadData();
        return data.word as WordRecord;
    }

    async function saveWordAndGenerateAudio() {
        const savedWord = await saveWord();
        if (!savedWord) return;

        await generateAudio(savedWord);
    }

    async function deleteWord(id: number) {
        const response = await fetch(`/api/words/${id}`, {method: "DELETE"});
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "删除题库失败");
            return;
        }

        toast.success("题库已删除");
        await loadData();
    }

    async function toggleWord(word: WordRecord) {
        const response = await fetch(`/api/words/${word.id}`, {
            method: "PUT",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify({...word, enabled: !word.enabled}),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "更新题库失败");
            return;
        }

        await loadData();
    }

    async function generateAudio(word: WordRecord) {
        const toastId = toast.loading(`正在生成 ${word.english} 的语音`);
        const response = await fetch(`/api/words/${word.id}/generate-audio`, {method: "POST"});
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "生成语音失败", {id: toastId});
            return;
        }

        toast.success(`${word.english} 的语音已生成`, {id: toastId});
        await loadData();
    }

    async function generateFilteredAudios() {
        if (filteredWords.length === 0 || batchAudioProgress.running) return;

        setBatchAudioProgress({
            running: true,
            total: filteredWords.length,
            done: 0,
            success: 0,
            failed: 0,
            current: "",
        });

        let success = 0;
        let failed = 0;

        for (let index = 0; index < filteredWords.length; index += 1) {
            const word = filteredWords[index];
            setBatchAudioProgress((progress) => ({
                ...progress,
                current: word.english,
            }));

            try {
                const response = await fetch(`/api/words/${word.id}/generate-audio`, {method: "POST"});
                if (response.ok) success += 1;
                else failed += 1;
            } catch {
                failed += 1;
            }

            setBatchAudioProgress({
                running: true,
                total: filteredWords.length,
                done: index + 1,
                success,
                failed,
                current: word.english,
            });
        }

        toast.success("当前词库语音生成完成", {
            description: `成功 ${success} 个，失败 ${failed} 个`,
        });
        setBatchAudioProgress({
            running: false,
            total: 0,
            done: 0,
            success: 0,
            failed: 0,
            current: "",
        });
        await loadData();
    }

    async function saveClassType() {
        const name = editingClassType ? editingClassType.name : classTypeName;
        const response = await fetch(editingClassType ? `/api/class-types/${editingClassType.id}` : "/api/class-types", {
            method: editingClassType ? "PUT" : "POST",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify({
                name,
                enabled: editingClassType?.enabled ?? true,
            }),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "保存班级类型失败");
            return;
        }

        toast.success(editingClassType ? "班级类型已更新" : "班级类型已添加");
        setClassTypeName("");
        setEditingClassType(null);
        await loadData();
    }

    async function deleteClassType(id: number) {
        const response = await fetch(`/api/class-types/${id}`, {method: "DELETE"});
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "删除班级类型失败");
            return;
        }

        toast.success("班级类型已删除");
        await loadData();
    }

    async function toggleClassType(classType: ClassType) {
        const response = await fetch(`/api/class-types/${classType.id}`, {
            method: "PUT",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify({name: classType.name, enabled: !classType.enabled}),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "更新班级类型失败");
            return;
        }

        await loadData();
    }

    async function saveSettings() {
        const response = await fetch("/api/settings", {
            method: "PUT",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify(settings),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "保存设置失败");
            return;
        }

        setSettings(mergeSettings(data.settings));
        setSettingsDialogOpen(false);
        toast.success("设置已保存");
    }

    async function previewTtsVoice() {
        const toastId = toast.loading("正在生成试听语音");
        const response = await fetch("/api/tts-preview", {
            method: "POST",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify({
                voice: settings.ttsVoice,
                rate: settings.ttsRate,
                text: "Hello, welcome to English PK.",
            }),
        });
        const data = await response.json();

        if (!response.ok) {
            toast.error(data.message ?? "试听语音失败", {id: toastId});
            return;
        }

        await new Audio(data.audio).play();
        toast.success("正在播放试听语音", {id: toastId});
    }

    return (
        <main className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:py-8">
            <div className="mb-5 flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
                <div>
                    <div
                        className="mb-2 inline-flex items-center gap-2 rounded-md bg-white px-3 py-1 text-sm font-medium text-slate-600 shadow-sm">
                        <Settings2 className="size-4"/>
                        后台管理
                    </div>
                    <h1 className="text-3xl font-bold tracking-tight text-slate-950 sm:text-4xl">English PK 管理台</h1>
                </div>
                <div className="flex flex-wrap gap-2">
                    <Button variant="outline" asChild>
                        <Link href="/pk">
                            <Gamepad2 className="size-4"/>
                            打开PK页面
                        </Link>
                    </Button>
                    <Button variant="outline" onClick={() => setSettingsDialogOpen(true)}>
                        <Settings2 className="size-4"/>
                        设置
                    </Button>
                    <Button onClick={loadData}>
                        <RefreshCw className="size-4"/>
                        刷新
                    </Button>
                </div>
            </div>

            <div className="grid gap-3 md:grid-cols-3">
                <Card>
                    <CardHeader className="p-4 pb-2">
                        <CardDescription>启用词库</CardDescription>
                        <CardTitle className="text-2xl">{enabledCount}</CardTitle>
                    </CardHeader>
                    <CardContent className="px-4 pb-4 text-xs text-muted-foreground">PK
                        页面会从启用词库中随机出题。</CardContent>
                </Card>
                <Card>
                    <CardHeader className="p-4 pb-2">
                        <CardDescription>总词库</CardDescription>
                        <CardTitle className="text-2xl">{wordList.length}</CardTitle>
                    </CardHeader>
                    <CardContent className="flex flex-wrap gap-1 px-4 pb-4">
                        {grades.map((grade) => (
                            <Badge key={grade} variant="secondary">
                                {grade}: {wordList.filter((word) => word.grade === grade).length}
                            </Badge>
                        ))}
                    </CardContent>
                </Card>
                <Card>
                    <CardHeader className="p-4 pb-2">
                        <CardDescription>已生成语音</CardDescription>
                        <CardTitle className="text-2xl">{audioCount}</CardTitle>
                    </CardHeader>
                    <CardContent
                        className="px-4 pb-4 text-xs text-muted-foreground">编辑单词后语音会清空，需要重新生成。</CardContent>
                </Card>
            </div>

            <div className="mt-5">
                <Card>
                    <CardHeader>
                        <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
                            <CardTitle>词库管理</CardTitle>
                            <div className="flex flex-wrap items-center gap-2">
                                {loading && <Badge variant="secondary">加载中</Badge>}
                                <Button variant="outline" onClick={openCreateWordDialog}>
                                    <Plus className="size-4"/>
                                    添加词库
                                </Button>
                                <Button
                                    variant="outline"
                                    onClick={generateFilteredAudios}
                                    disabled={batchAudioProgress.running || filteredWords.length === 0}
                                >
                                    <Mic2 className="size-4"/>
                                    一键生成当前词库语音
                                </Button>
                            </div>
                        </div>
                    </CardHeader>
                    <CardContent>
                        {batchAudioProgress.running && (
                            <div className="mb-5 rounded-lg border bg-white p-4">
                                <div
                                    className="mb-2 flex flex-col gap-1 text-sm sm:flex-row sm:items-center sm:justify-between">
                                    <div className="font-medium text-slate-800">
                                        正在生成：{batchAudioProgress.current || "准备中"}
                                    </div>
                                    <div className="text-slate-500">
                                        {batchAudioProgress.done}/{batchAudioProgress.total}
                                        <span className="ml-3 text-emerald-600">成功 {batchAudioProgress.success}</span>
                                        <span className="ml-3 text-red-500">失败 {batchAudioProgress.failed}</span>
                                    </div>
                                </div>
                                <div className="h-3 overflow-hidden rounded-full bg-slate-100">
                                    <div
                                        className="h-full rounded-full bg-emerald-500 transition-all"
                                        style={{
                                            width:
                                                batchAudioProgress.total === 0
                                                    ? "0%"
                                                    : `${Math.round((batchAudioProgress.done / batchAudioProgress.total) * 100)}%`,
                                        }}
                                    />
                                </div>
                            </div>
                        )}

                        <div className="mb-4 flex flex-col gap-3 lg:flex-row">
                            <div className="relative flex-1">
                                <Search
                                    className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground"/>
                                <Input
                                    value={query}
                                    onChange={(event) => setQuery(event.target.value)}
                                    placeholder="搜索题库英语"
                                    className="pl-9"
                                />
                            </div>
                            <select
                                value={gradeFilter}
                                onChange={(event) => setGradeFilter(event.target.value as "all" | Grade)}
                                className="h-10 rounded-md border bg-white px-3 text-sm"
                            >
                                <option value="all">全部年级</option>
                                {grades.map((grade) => (
                                    <option key={grade} value={grade}>
                                        {grade}
                                    </option>
                                ))}
                            </select>
                            <select
                                value={classTypeFilter}
                                onChange={(event) =>
                                    setClassTypeFilter(event.target.value === "all" ? "all" : Number(event.target.value))
                                }
                                className="h-10 rounded-md border bg-white px-3 text-sm"
                            >
                                <option value="all">全部班型</option>
                                {classTypes.map((classType) => (
                                    <option key={classType.id} value={classType.id}>
                                        {classType.name}
                                    </option>
                                ))}
                            </select>
                        </div>

                        <Table>
                            <TableHeader>
                                <TableRow>
                                    <TableHead>年级</TableHead>
                                    <TableHead>班级类型</TableHead>
                                    <TableHead>图标/图片</TableHead>
                                    <TableHead>题库英语</TableHead>
                                    <TableHead>中文</TableHead>
                                    <TableHead>语音</TableHead>
                                    <TableHead>状态</TableHead>
                                    <TableHead className="text-right">操作</TableHead>
                                </TableRow>
                            </TableHeader>
                            <TableBody>
                                {filteredWords.map((word) => (
                                    <TableRow key={word.id}>
                                        <TableCell>
                                            <Badge variant="outline">{word.grade}</Badge>
                                        </TableCell>
                                        <TableCell>{word.classTypeName}</TableCell>
                                        <TableCell>
                                            <WordImagePreview value={word.image}/>
                                        </TableCell>
                                        <TableCell className="font-semibold">{word.english}</TableCell>
                                        <TableCell>{word.chinese ||
                                            <span className="text-muted-foreground">未设置</span>}</TableCell>
                                        <TableCell>
                                            {word.audio ? (
                                                <Button variant="outline" size="sm"
                                                        onClick={() => new Audio(word.audio).play()}>
                                                    <Play className="size-4"/>
                                                    试听
                                                </Button>
                                            ) : (
                                                <Button variant="outline" size="sm" onClick={() => generateAudio(word)}>
                                                    <Mic2 className="size-4"/>
                                                    生成
                                                </Button>
                                            )}
                                        </TableCell>
                                        <TableCell>
                                            <Switch checked={word.enabled} onClick={() => toggleWord(word)}/>
                                        </TableCell>
                                        <TableCell className="text-right">
                                            <div className="flex justify-end gap-2">
                                                <Button variant="outline" size="icon"
                                                        onClick={() => openEditWordDialog(word)}>
                                                    <Pencil className="size-4"/>
                                                </Button>
                                                <Button variant="outline" size="icon"
                                                        onClick={() => generateAudio(word)}>
                                                    <Mic2 className="size-4"/>
                                                </Button>
                                                <Button variant="destructive" size="icon"
                                                        onClick={() => deleteWord(word.id)}>
                                                    <Trash2 className="size-4"/>
                                                </Button>
                                            </div>
                                        </TableCell>
                                    </TableRow>
                                ))}
                            </TableBody>
                        </Table>
                    </CardContent>
                </Card>
            </div>

            <Dialog open={wordDialogOpen} onOpenChange={setWordDialogOpen}>
                <DialogContent className="max-w-2xl">
                    <DialogHeader>
                        <DialogTitle>{wordForm.id ? "编辑词库" : "添加词库"}</DialogTitle>
                        <DialogDescription>编辑英语内容后，原语音会清空并需要重新生成。</DialogDescription>
                    </DialogHeader>
                    <div className="grid gap-4 sm:grid-cols-2">
                        <label className="space-y-2 text-sm font-medium">
                            年级
                            <select
                                value={wordForm.grade}
                                onChange={(event) => setWordForm((form) => ({
                                    ...form,
                                    grade: event.target.value as Grade
                                }))}
                                className="h-10 w-full rounded-md border bg-white px-3 text-sm"
                            >
                                {grades.map((grade) => (
                                    <option key={grade} value={grade}>
                                        {grade}
                                    </option>
                                ))}
                            </select>
                        </label>
                        <label className="space-y-2 text-sm font-medium">
                            班级类型
                            <select
                                value={wordForm.classTypeId}
                                onChange={(event) => setWordForm((form) => ({
                                    ...form,
                                    classTypeId: Number(event.target.value)
                                }))}
                                className="h-10 w-full rounded-md border bg-white px-3 text-sm"
                            >
                                {classTypes.map((classType) => (
                                    <option key={classType.id} value={classType.id}>
                                        {classType.name}
                                    </option>
                                ))}
                            </select>
                        </label>
                        <label className="space-y-2 text-sm font-medium">
                            题库英语
                            <Input
                                value={wordForm.english}
                                onChange={(event) => setWordForm((form) => ({...form, english: event.target.value}))}
                                placeholder="apple"
                            />
                        </label>
                        <label className="space-y-2 text-sm font-medium">
                            中文
                            <Input
                                value={wordForm.chinese}
                                onChange={(event) => setWordForm((form) => ({...form, chinese: event.target.value}))}
                                placeholder="苹果"
                            />
                        </label>
                        <label className="space-y-2 text-sm font-medium">
                            图标/图片
                            <Input
                                value={wordForm.image}
                                onChange={(event) => setWordForm((form) => ({...form, image: event.target.value}))}
                                placeholder="🍎 或 /apple.png"
                            />
                        </label>
                        <div className="flex items-center justify-between rounded-md border p-3 sm:col-span-2">
                            <div>
                                <div className="font-medium">是否启用</div>
                                <div className="text-sm text-muted-foreground">停用后不会进入 PK 题库。</div>
                            </div>
                            <Switch
                                checked={wordForm.enabled}
                                onClick={() => setWordForm((form) => ({...form, enabled: !form.enabled}))}
                            />
                        </div>
                    </div>
                    <DialogFooter>
                        <Button variant="outline" onClick={saveWordAndGenerateAudio}>
                            <Mic2 className="size-4"/>
                            保存并生成语音
                        </Button>
                        <Button onClick={saveWord}>
                            <Save className="size-4"/>
                            保存
                        </Button>
                    </DialogFooter>
                </DialogContent>
            </Dialog>

            <Dialog open={settingsDialogOpen} onOpenChange={setSettingsDialogOpen}>
                <DialogContent className="max-w-4xl">
                    <DialogHeader>
                        <DialogTitle>设置</DialogTitle>
                        <DialogDescription>配置语音、课堂规则、班级类型和 PK 页面入口。</DialogDescription>
                    </DialogHeader>
                    <div className="grid min-h-[460px] gap-4 md:grid-cols-[220px_1fr]">
                        <div
                            className="flex gap-2 overflow-x-auto rounded-lg border bg-slate-50 p-2 md:flex-col md:overflow-visible">
                            {settingsSections.map((section) => {
                                const Icon = section.icon;
                                const active = settingsSection === section.id;
                                return (
                                    <button
                                        key={section.id}
                                        type="button"
                                        onClick={() => setSettingsSection(section.id)}
                                        className={`flex min-w-[160px] items-start gap-3 rounded-md px-3 py-3 text-left text-sm transition md:min-w-0 ${
                                            active ? "bg-white text-blue-700 shadow-sm" : "text-slate-600 hover:bg-white/70 hover:text-slate-900"
                                        }`}
                                    >
                                        <Icon className="mt-0.5 size-4 shrink-0"/>
                                        <span>
                      <span className="block font-semibold">{section.label}</span>
                      <span className="mt-1 block text-xs text-muted-foreground">{section.description}</span>
                    </span>
                                    </button>
                                );
                            })}
                        </div>

                        <div className="rounded-lg border bg-white p-5">
                            {settingsSection === "voice" && (
                                <div className="space-y-5">
                                    <div>
                                        <h3 className="text-lg font-semibold">语音设置</h3>
                                        <p className="mt-1 text-sm text-muted-foreground">用于生成单词音频，也会用于 PK
                                            页面缺少音频时的生成。</p>
                                    </div>
                                    <div className="space-y-2 text-sm font-medium">
                                        <div>Edge TTS 声音</div>
                                        <div className="flex gap-2">
                                            <select
                                                value={settings.ttsVoice}
                                                onChange={(event) => setSettings((value) => ({
                                                    ...value,
                                                    ttsVoice: event.target.value
                                                }))}
                                                className="h-10 flex-1 rounded-md border bg-white px-3 text-sm"
                                            >
                                                {ttsVoiceOptions.map((voice) => (
                                                    <option key={voice.value} value={voice.value}>
                                                        {voice.label}
                                                    </option>
                                                ))}
                                            </select>
                                            <Button variant="outline" onClick={previewTtsVoice}>
                                                <Play className="size-4"/>
                                                试听
                                            </Button>
                                        </div>
                                    </div>
                                    <label className="block space-y-2 text-sm font-medium">
                                        语速
                                        <select
                                            value={settings.ttsRate}
                                            onChange={(event) => setSettings((value) => ({
                                                ...value,
                                                ttsRate: event.target.value
                                            }))}
                                            className="h-10 w-full rounded-md border bg-white px-3 text-sm"
                                        >
                                            {ttsRateOptions.map((rate) => (
                                                <option key={rate.value} value={rate.value}>
                                                    {rate.label}
                                                </option>
                                            ))}
                                        </select>
                                    </label>
                                </div>
                            )}

                            {settingsSection === "rules" && (
                                <div className="space-y-5">
                                    <div>
                                        <h3 className="text-lg font-semibold">课堂规则</h3>
                                        <p className="mt-1 text-sm text-muted-foreground">控制 PK
                                            页面计分规则和自动播放行为。</p>
                                    </div>
                                    <div className="grid gap-3 sm:grid-cols-2">
                                        <label className="space-y-2 text-sm font-medium">
                                            答对加分
                                            <Input
                                                type="number"
                                                min={1}
                                                value={settings.scorePerCorrect}
                                                onChange={(event) =>
                                                    setSettings((value) => ({
                                                        ...value,
                                                        scorePerCorrect: Number(event.target.value)
                                                    }))
                                                }
                                            />
                                        </label>
                                        <label className="space-y-2 text-sm font-medium">
                                            答错扣分
                                            <Input
                                                type="number"
                                                min={0}
                                                value={settings.scorePerWrong}
                                                onChange={(event) =>
                                                    setSettings((value) => ({
                                                        ...value,
                                                        scorePerWrong: Number(event.target.value)
                                                    }))
                                                }
                                            />
                                        </label>
                                        <label className="space-y-2 text-sm font-medium">
                                            PK 显示单词数
                                            <Input
                                                type="number"
                                                min={0}
                                                value={settings.pkWordCount}
                                                onChange={(event) =>
                                                    setSettings((value) => ({
                                                        ...value,
                                                        pkWordCount: Number(event.target.value)
                                                    }))
                                                }
                                            />
                                            <span className="block text-xs font-normal text-muted-foreground">
                                                填 0 表示使用当前题库全部单词。
                                            </span>
                                        </label>
                                        <label className="space-y-2 text-sm font-medium">
                                            PK 选项数量
                                            <Input
                                                type="number"
                                                min={2}
                                                max={8}
                                                step={2}
                                                value={settings.pkOptionCount}
                                                onChange={(event) =>
                                                    setSettings((value) => ({
                                                        ...value,
                                                        pkOptionCount: Number(event.target.value)
                                                    }))
                                                }
                                            />
                                            <span className="block text-xs font-normal text-muted-foreground">
                                                建议使用双数，如 2、4、6，保存时会自动修正。
                                            </span>
                                        </label>
                                    </div>
                                    <div className="flex items-center justify-between rounded-md border p-3">
                                        <div>
                                            <div className="font-medium">自动朗读</div>
                                            <div className="text-sm text-muted-foreground">每题开始时播放单词。</div>
                                        </div>
                                        <Switch
                                            checked={settings.autoSpeak}
                                            onClick={() => setSettings((value) => ({
                                                ...value,
                                                autoSpeak: !value.autoSpeak
                                            }))}
                                        />
                                    </div>
                                    <label className="block space-y-2 text-sm font-medium">
                                        PK 单词显示
                                        <select
                                            value={settings.wordDisplayMode}
                                            onChange={(event) =>
                                                setSettings((value) => ({
                                                    ...value,
                                                    wordDisplayMode: event.target.value as AppSettings["wordDisplayMode"],
                                                }))
                                            }
                                            className="h-10 w-full rounded-md border bg-white px-3 text-sm"
                                        >
                                            {wordDisplayModeOptions.map((mode) => (
                                                <option key={mode.value} value={mode.value}>
                                                    {mode.label}
                                                </option>
                                            ))}
                                        </select>
                                    </label>
                                </div>
                            )}

                            {settingsSection === "classTypes" && (
                                <div className="space-y-5">
                                    <div>
                                        <h3 className="text-lg font-semibold">班级类型</h3>
                                        <p className="mt-1 text-sm text-muted-foreground">这里可以定制班级类型，PK
                                            页面会读取启用项。</p>
                                    </div>
                                    <div className="flex gap-2">
                                        <Input
                                            value={editingClassType ? editingClassType.name : classTypeName}
                                            onChange={(event) =>
                                                editingClassType
                                                    ? setEditingClassType({
                                                        ...editingClassType,
                                                        name: event.target.value
                                                    })
                                                    : setClassTypeName(event.target.value)
                                            }
                                            placeholder="班级类型名称"
                                        />
                                        <Button onClick={saveClassType}>{editingClassType ? "保存" : "添加"}</Button>
                                        {editingClassType && (
                                            <Button variant="outline" onClick={() => setEditingClassType(null)}>
                                                取消
                                            </Button>
                                        )}
                                    </div>

                                    <div className="space-y-2">
                                        {classTypes.map((classType) => (
                                            <div key={classType.id}
                                                 className="flex items-center justify-between rounded-md border p-3">
                                                <div>
                                                    <div className="font-medium">{classType.name}</div>
                                                    <div
                                                        className="text-xs text-muted-foreground">{classType.enabled ? "已启用" : "已停用"}</div>
                                                </div>
                                                <div className="flex items-center gap-2">
                                                    <Switch checked={classType.enabled}
                                                            onClick={() => toggleClassType(classType)}/>
                                                    <Button variant="outline" size="icon"
                                                            onClick={() => setEditingClassType(classType)}>
                                                        <Pencil className="size-4"/>
                                                    </Button>
                                                    <Button variant="destructive" size="icon"
                                                            onClick={() => deleteClassType(classType.id)}>
                                                        <Trash2 className="size-4"/>
                                                    </Button>
                                                </div>
                                            </div>
                                        ))}
                                    </div>
                                </div>
                            )}

                            {settingsSection === "preview" && (
                                <div className="space-y-5">
                                    <div>
                                        <h3 className="text-lg font-semibold">页面预览</h3>
                                        <p className="mt-1 text-sm text-muted-foreground">打开比赛页面检查课堂展示效果。</p>
                                    </div>
                                    <Button asChild className="w-full sm:w-auto">
                                        <Link href="/pk">
                                            <Eye className="size-4"/>
                                            预览PK页面
                                        </Link>
                                    </Button>
                                </div>
                            )}
                        </div>
                    </div>
                    <DialogFooter>
                        <Button onClick={saveSettings}>
                            <Save className="size-4"/>
                            保存设置
                        </Button>
                    </DialogFooter>
                </DialogContent>
            </Dialog>
        </main>
    );
}

function WordImagePreview({value}: { value: string }) {
    if (!value) {
        return <span className="text-sm text-muted-foreground">未设置</span>;
    }

    if (isImageSource(value)) {
        return <img src={value} alt="" className="size-12 rounded-md border bg-white object-contain p-1"/>;
    }

    return <span className="text-3xl leading-none">{value}</span>;
}

function isImageSource(value: string) {
    return /^(https?:\/\/|\/|data:image\/)/i.test(value);
}

function mergeSettings(settings: Partial<AppSettings>): AppSettings {
    return {
        ttsVoice: settings.ttsVoice || defaultSettings.ttsVoice,
        ttsRate: settings.ttsRate || defaultSettings.ttsRate,
        scorePerCorrect: Number(settings.scorePerCorrect ?? defaultSettings.scorePerCorrect),
        scorePerWrong: Number(settings.scorePerWrong ?? defaultSettings.scorePerWrong),
        autoSpeak: settings.autoSpeak ?? defaultSettings.autoSpeak,
        wordDisplayMode:
            settings.wordDisplayMode === "capitalize" ||
            settings.wordDisplayMode === "input" ||
            settings.wordDisplayMode === "uppercase"
                ? settings.wordDisplayMode
                : defaultSettings.wordDisplayMode,
        pkWordCount: Math.max(0, Math.floor(Number(settings.pkWordCount ?? defaultSettings.pkWordCount))),
        pkOptionCount: normalizeOptionCount(Number(settings.pkOptionCount ?? defaultSettings.pkOptionCount)),
    };
}

function normalizeOptionCount(value: number) {
    const count = Math.floor(value);
    if (!Number.isFinite(count)) return defaultSettings.pkOptionCount;
    if (count < 2) return 2;
    if (count > 8) return 8;
    return count % 2 === 0 ? count : count + 1;
}
