"use client";

import { useState, useCallback, useRef, useEffect } from "react";
import { TestTube, Loader2, Download, CheckCircle2, AlertCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { toast } from "sonner";

const API_PREFIX = "/api/testcase-generator";

interface GenerateRequest {
  title: string;
  englishName: string;
  description: string;
  standardCode: string;
  serviceLevel: string;
  testCaseCount: number;
}

interface TaskStatusResponse {
  task_id: string;
  status: "pending" | "running" | "completed" | "failed";
  progress?: number;
  title?: string;
  english_name?: string;
  test_case_count?: number;
  generated_cases?: number;
  error_message?: string;
  currentMessage?: string;
}

interface CompletedResult {
  title?: string;
  english_name?: string;
  test_case_count?: number;
  file_size?: string;
}

export default function TestcaseGeneratorPage() {
  const [problemTitle, setProblemTitle] = useState("");
  const [problemSlug, setProblemSlug] = useState("");
  const [problemDescription, setProblemDescription] = useState("");
  const [stdProgram, setStdProgram] = useState("");
  const [serviceLevel, setServiceLevel] = useState<"standard" | "pro">("standard");
  const [testCaseCount, setTestCaseCount] = useState(10);

  const [isGenerating, setIsGenerating] = useState(false);
  const [progressOpen, setProgressOpen] = useState(false);
  const [progressTitle, setProgressTitle] = useState("正在生成测试数据");
  const [progressMessage, setProgressMessage] = useState("请稍候...");
  const [progressPercent, setProgressPercent] = useState(0);
  const [progressTaskId, setProgressTaskId] = useState("");
  const [progressGenerated, setProgressGenerated] = useState(0);
  const [progressTotal, setProgressTotal] = useState(0);
  const [progressRunningTime, setProgressRunningTime] = useState(0);
  const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const startTimeRef = useRef(0);

  const [resultModalOpen, setResultModalOpen] = useState(false);
  const [resultData, setResultData] = useState<CompletedResult & { task_id?: string } | null>(null);
  const [errorBlock, setErrorBlock] = useState<{ title: string; message: string } | null>(null);

  const slugPattern = /^[a-z][a-z0-9_]*$/;

  const showProgress = useCallback(() => {
    setProgressOpen(true);
    setProgressPercent(0);
    setProgressGenerated(0);
    setProgressTotal(0);
    setProgressRunningTime(0);
    setProgressTaskId("");
    startTimeRef.current = Date.now();
  }, []);

  const hideProgress = useCallback(() => {
    setProgressOpen(false);
    if (pollTimerRef.current) {
      clearTimeout(pollTimerRef.current);
      pollTimerRef.current = null;
    }
  }, []);

  const updateProgress = useCallback(
    (opts: {
      title?: string;
      message?: string;
      progress?: number;
      taskId?: string;
      generatedCount?: number;
      totalCount?: number;
    }) => {
      if (opts.title !== undefined) setProgressTitle(opts.title);
      if (opts.message !== undefined) setProgressMessage(opts.message);
      if (opts.progress !== undefined) setProgressPercent(Math.min(100, Math.max(0, opts.progress)));
      if (opts.taskId !== undefined) setProgressTaskId(opts.taskId);
      if (opts.generatedCount !== undefined) setProgressGenerated(opts.generatedCount);
      if (opts.totalCount !== undefined) setProgressTotal(opts.totalCount);
    },
    []
  );

  const pollTaskStatus = useCallback(
    async (taskId: string, problemTitle: string, estimatedTimeSec: number) => {
      const tick = () => {
        setProgressRunningTime(Math.floor((Date.now() - startTimeRef.current) / 1000));
      };
      const interval = setInterval(tick, 1000);

      const check = async () => {
        try {
          const res = await fetch(`${API_PREFIX}/task_status/${taskId}`);
          const data: TaskStatusResponse = await res.json();
          updateProgress({
            progress: data.progress ?? 0,
            generatedCount: data.generated_cases ?? 0,
            totalCount: data.test_case_count ?? 0,
            message: data.currentMessage || "正在处理...",
          });

          if (data.status === "completed") {
            clearInterval(interval);
            hideProgress();
            setIsGenerating(false);
            setResultData({
              title: data.title ?? problemTitle,
              english_name: data.english_name,
              test_case_count: data.test_case_count,
              file_size: "计算中...",
              task_id: taskId,
            });
            setResultModalOpen(true);
            setErrorBlock(null);
            toast.success("测试数据生成完成！");
            return;
          }

          if (data.status === "failed") {
            clearInterval(interval);
            hideProgress();
            setIsGenerating(false);
            setErrorBlock({
              title: "测试数据生成失败",
              message: data.error_message || "未知错误",
            });
            toast.error("测试数据生成失败");
            return;
          }

          pollTimerRef.current = setTimeout(check, 2000);
        } catch (err) {
          clearInterval(interval);
          hideProgress();
          setIsGenerating(false);
          const msg = err instanceof Error ? err.message : String(err);
          toast.error("获取任务状态失败: " + msg);
        }
      };

      await check();
    },
    [updateProgress, hideProgress]
  );

  const handleGenerate = useCallback(async () => {
    const title = problemTitle.trim();
    const slug = problemSlug.trim();
    const description = problemDescription.trim();
    const code = stdProgram.trim();

    if (!title || !slug || !description || !code) {
      toast.error("请填写所有必填字段");
      return;
    }
    if (!slugPattern.test(slug)) {
      toast.error("题目英文名只能包含小写字母、数字和下划线，且必须以字母开头");
      return;
    }
    const count = Math.min(50, Math.max(1, testCaseCount));
    if (count !== testCaseCount) setTestCaseCount(count);

    setIsGenerating(true);
    setErrorBlock(null);
    showProgress();
    updateProgress({ title: "正在生成测试数据", message: "正在初始化...", taskId: "" });

    try {
      const body: GenerateRequest = {
        title,
        englishName: slug,
        description,
        standardCode: code,
        serviceLevel,
        testCaseCount: count,
      };
      const res = await fetch(`${API_PREFIX}/generate`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      const result = await res.json();

      if (!res.ok) {
        throw new Error(result.error || result.message || "生成请求失败");
      }

      if (result.success && result.task_id) {
        const estimatedTime = result.estimated_time ?? 60;
        updateProgress({
          taskId: result.task_id,
          title: `正在生成「${title}」的测试数据`,
          message: `预计需要 ${Math.ceil(estimatedTime / 60)} 分钟，请耐心等待...`,
          totalCount: count,
        });
        await pollTaskStatus(result.task_id, title, estimatedTime);
      } else {
        throw new Error(result.error || "未返回任务 ID");
      }
    } catch (err) {
      hideProgress();
      setIsGenerating(false);
      const msg = err instanceof Error ? err.message : String(err);
      toast.error("生成失败: " + msg);
    }
  }, [
    problemTitle,
    problemSlug,
    problemDescription,
    stdProgram,
    serviceLevel,
    testCaseCount,
    showProgress,
    updateProgress,
    hideProgress,
    pollTaskStatus,
  ]);

  const handleCancelGeneration = useCallback(() => {
    hideProgress();
    setIsGenerating(false);
    toast.info("生成已取消");
  }, [hideProgress]);

  const handleDownload = useCallback((taskId: string) => {
    if (!taskId) return;
    const url = `${API_PREFIX}/download/${taskId}`;
    window.open(url, "_blank");
    toast.success("开始下载测试数据");
  }, []);

  const handleCloseResultModal = useCallback(() => {
    setResultModalOpen(false);
    setResultData(null);
  }, []);

  useEffect(() => {
    return () => {
      if (pollTimerRef.current) clearTimeout(pollTimerRef.current);
    };
  }, []);

  const runningTimeStr =
    progressRunningTime >= 60
      ? `${Math.floor(progressRunningTime / 60)}分${progressRunningTime % 60}秒`
      : `${progressRunningTime}秒`;

  return (
    <div className="space-y-8 max-w-3xl mx-auto">
      <div className="text-center space-y-2">
        <h1 className="text-3xl font-bold flex items-center justify-center gap-2">
          <TestTube className="h-8 w-8 text-purple-500" />
          测试数据生成
        </h1>
        <p className="text-muted-foreground">
          为信息学奥林匹克竞赛生成高质量测试数据
        </p>
      </div>

      {/* 题目信息 */}
      <Card>
        <CardHeader>
          <CardTitle>题目信息</CardTitle>
        </CardHeader>
        <CardContent className="space-y-6">
          <div className="space-y-2">
            <Label>
              题目标题 <span className="text-destructive">*</span>
            </Label>
            <Input
              placeholder="例如：A+B Problem"
              value={problemTitle}
              onChange={(e) => setProblemTitle(e.target.value)}
            />
            <p className="text-xs text-muted-foreground">简短描述题目名称</p>
          </div>
          <div className="space-y-2">
            <Label>
              题目英文名 <span className="text-destructive">*</span>
            </Label>
            <Input
              placeholder="例如：aplusb"
              value={problemSlug}
              onChange={(e) => setProblemSlug(e.target.value.toLowerCase())}
            />
            <p className="text-xs text-muted-foreground">
              用作文件名前缀，只能包含小写字母、数字和下划线，必须以字母开头
            </p>
          </div>
          <div className="space-y-2">
            <Label>
              题目描述 <span className="text-destructive">*</span>
            </Label>
            <Textarea
              placeholder={`请输入完整的题目描述，包括：
- 题目背景和要求
- 输入格式
- 输出格式
- 数据范围和约束条件
- 样例输入输出`}
              className="min-h-[200px] resize-y"
              value={problemDescription}
              onChange={(e) => setProblemDescription(e.target.value)}
            />
            <p className="text-xs text-muted-foreground">
              详细描述题目要求，包括输入输出格式、数据范围等
            </p>
          </div>
        </CardContent>
      </Card>

      {/* 标准程序 */}
      <Card>
        <CardHeader>
          <CardTitle>
            标准程序 (C++) <span className="text-destructive">*</span>
          </CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <Label>C++ 标准程序代码</Label>
          <Textarea
            placeholder={`请输入 C++ 标准程序代码，例如：

#include <iostream>
using namespace std;

int main() {
    int a, b;
    cin >> a >> b;
    cout << a + b << endl;
    return 0;
}

注意：从标准输入读取数据，结果输出到标准输出。`}
            className="min-h-[280px] font-mono text-sm resize-y"
            value={stdProgram}
            onChange={(e) => setStdProgram(e.target.value)}
          />
          <div className="rounded-lg border border-blue-200 bg-blue-50 dark:bg-blue-950/30 dark:border-blue-800 p-4 text-sm text-blue-900 dark:text-blue-200">
            <p className="font-semibold mb-2">标程说明</p>
            <ul className="list-disc list-inside space-y-1 opacity-90">
              <li>标程用于为生成的输入数据 (.in) 生成正确的输出数据 (.out)</li>
              <li>请确保代码逻辑正确，能处理边界情况</li>
              <li>系统将使用 g++ 编译您的代码</li>
              <li>运行限制：内存 512MB，栈 512MB，时间 30 秒/测试点</li>
            </ul>
          </div>
        </CardContent>
      </Card>

      {/* 生成配置 */}
      <Card>
        <CardHeader>
          <CardTitle>生成配置</CardTitle>
        </CardHeader>
        <CardContent className="space-y-6">
          <div className="space-y-2">
            <Label>测试点数量</Label>
            <div className="flex items-center gap-4 flex-wrap">
              <Input
                type="number"
                min={1}
                max={50}
                value={testCaseCount}
                onChange={(e) =>
                  setTestCaseCount(parseInt(e.target.value, 10) || 10)
                }
                className="w-28"
              />
              <p className="text-sm text-muted-foreground">
                建议 1–50 个测试点，数量越多生成时间越长
              </p>
            </div>
          </div>
          <div className="space-y-2">
            <Label>生成模式</Label>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <button
                type="button"
                onClick={() => setServiceLevel("standard")}
                className={`flex items-start gap-3 rounded-xl border-2 p-5 text-left transition-all ${
                  serviceLevel === "standard"
                    ? "border-primary bg-primary/5"
                    : "border-border hover:border-muted-foreground/50"
                }`}
              >
                <input
                  type="radio"
                  name="service_level"
                  checked={serviceLevel === "standard"}
                  readOnly
                  className="mt-1"
                />
                <div>
                  <p className="font-semibold">标准版</p>
                  <p className="text-sm text-muted-foreground">基础测试数据生成</p>
                </div>
              </button>
              <button
                type="button"
                onClick={() => setServiceLevel("pro")}
                className={`flex items-start gap-3 rounded-xl border-2 p-5 text-left transition-all ${
                  serviceLevel === "pro"
                    ? "border-primary bg-primary/5"
                    : "border-border hover:border-muted-foreground/50"
                }`}
              >
                <input
                  type="radio"
                  name="service_level"
                  checked={serviceLevel === "pro"}
                  readOnly
                  className="mt-1"
                />
                <div>
                  <p className="font-semibold">专业版</p>
                  <p className="text-sm text-muted-foreground">高质量智能生成</p>
                </div>
              </button>
            </div>
          </div>
        </CardContent>
      </Card>

      {/* 提交 */}
      <div className="flex justify-center">
        <Button
          size="lg"
          onClick={handleGenerate}
          disabled={isGenerating}
          className="gap-2"
        >
          {isGenerating ? (
            <>
              <Loader2 className="h-5 w-5 animate-spin" />
              生成中...
            </>
          ) : (
            "开始生成"
          )}
        </Button>
      </div>

      {/* 错误信息块 */}
      {errorBlock && (
        <Card className="border-destructive/50 bg-destructive/5">
          <CardContent className="pt-6">
            <div className="flex items-start gap-4">
              <div className="rounded-full bg-destructive/10 p-3">
                <AlertCircle className="h-6 w-6 text-destructive" />
              </div>
              <div className="flex-1">
                <h4 className="font-semibold text-destructive">{errorBlock.title}</h4>
                <p className="text-sm text-muted-foreground mt-1">{errorBlock.message}</p>
                <p className="text-sm text-amber-700 dark:text-amber-400 mt-4">
                  建议：检查题目描述与标准程序是否完整正确，稍后重试或联系技术支持。
                </p>
              </div>
            </div>
          </CardContent>
        </Card>
      )}

      {/* 进度遮罩 */}
      {progressOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4">
          <Card className="w-full max-w-md shadow-xl">
            <CardContent className="pt-6">
              <div className="flex items-center gap-3 mb-4">
                <div className="rounded-full bg-primary/10 p-3">
                  <Loader2 className="h-6 w-6 text-primary animate-spin" />
                </div>
                <div>
                  <h3 className="font-semibold">{progressTitle}</h3>
                  <p className="text-sm text-muted-foreground">{progressMessage}</p>
                </div>
              </div>
              <div className="space-y-2 mb-4">
                <div className="flex justify-between text-sm">
                  <span>进度</span>
                  <span>{Math.round(progressPercent)}%</span>
                </div>
                <div className="h-2 rounded-full bg-muted overflow-hidden">
                  <div
                    className="h-full bg-primary transition-all duration-300"
                    style={{ width: `${progressPercent}%` }}
                  />
                </div>
              </div>
              <div className="text-xs text-muted-foreground space-y-1 mb-4">
                <div className="flex justify-between">
                  <span>任务 ID</span>
                  <span className="font-mono">{progressTaskId || "-"}</span>
                </div>
                <div className="flex justify-between">
                  <span>已生成</span>
                  <span>
                    {progressGenerated}/{progressTotal}
                  </span>
                </div>
                <div className="flex justify-between">
                  <span>运行时间</span>
                  <span>{runningTimeStr}</span>
                </div>
              </div>
              <Button variant="outline" className="w-full" onClick={handleCancelGeneration}>
                取消生成
              </Button>
            </CardContent>
          </Card>
        </div>
      )}

      {/* 结果弹窗 */}
      <Dialog open={resultModalOpen} onOpenChange={(open) => !open && handleCloseResultModal()}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>生成完成</DialogTitle>
          </DialogHeader>
          {resultData && (
            <div className="space-y-4">
              <div className="flex items-center gap-3 rounded-lg border border-green-200 bg-green-50 dark:bg-green-950/30 dark:border-green-800 p-4">
                <CheckCircle2 className="h-10 w-10 text-green-600 shrink-0" />
                <div>
                  <p className="font-semibold text-green-800 dark:text-green-200">
                    测试数据已成功生成并打包为 ZIP 文件
                  </p>
                </div>
              </div>
              <div className="grid grid-cols-2 gap-2 text-sm">
                <span className="text-muted-foreground">题目名称</span>
                <span className="font-medium">{resultData.title ?? "—"}</span>
                <span className="text-muted-foreground">测试点数量</span>
                <span className="font-medium">{resultData.test_case_count ?? "—"} 个</span>
                <span className="text-muted-foreground">生成时间</span>
                <span className="font-medium">{new Date().toLocaleString("zh-CN")}</span>
                <span className="text-muted-foreground">文件大小</span>
                <span className="font-medium">{resultData.file_size ?? "—"}</span>
              </div>
              <div className="flex gap-2">
                <Button
                  className="gap-2 flex-1"
                  onClick={() => resultData.task_id && handleDownload(resultData.task_id)}
                >
                  <Download className="h-4 w-4" />
                  下载测试数据
                </Button>
                <Button variant="outline" onClick={handleCloseResultModal}>
                  关闭
                </Button>
              </div>
            </div>
          )}
        </DialogContent>
      </Dialog>
    </div>
  );
}
