import {
  CheckCircleFilled,
  CopyOutlined,
  DownloadOutlined,
  FileTextOutlined,
  UploadOutlined,
} from "@ant-design/icons";
import { useEffect, useRef, useState, type ChangeEvent, type KeyboardEvent } from "react";
import { evaluateScript } from "../../api/scriptEvalClient";
import { useSessionStore } from "../../stores";

interface ScoreDimension {
  key: string;
  label: string;
  maxScore: number;
  hint: string;
  detail: string;
}

interface EvalResult {
  totalScore: number;
  grade: string;
  dimensionScores: Record<string, number>;
  summary: string;
  issues: string[];
  highlights: string[];
  suggestions: string[];
}

interface HistoryEntry {
  name: string;
  date: string;
  timestamp: number;
  score: number;
  grade: string;
}

function getGrade(score: number): string {
  if (score >= 97) return "S+";
  if (score >= 93) return "S";
  if (score >= 88) return "A+";
  if (score >= 83) return "A";
  if (score >= 78) return "B+";
  if (score >= 70) return "B";
  return "C";
}

const HISTORY_KEY = "omniai:script-eval-history";
const TEXT_FILE_EXTENSIONS = [
  ".txt",
  ".text",
  ".md",
  ".markdown",
  ".fountain",
  ".fdx",
  ".rtf",
  ".csv",
  ".tsv",
  ".json",
  ".jsonl",
  ".xml",
  ".html",
  ".htm",
  ".yaml",
  ".yml",
  ".toml",
  ".ini",
  ".conf",
  ".cfg",
  ".properties",
  ".log",
  ".srt",
  ".ass",
  ".ssa",
  ".vtt",
  ".sql",
  ".js",
  ".jsx",
  ".ts",
  ".tsx",
  ".py",
  ".java",
  ".c",
  ".cpp",
  ".h",
  ".hpp",
  ".cs",
  ".go",
  ".rs",
  ".php",
  ".rb",
  ".sh",
  ".bat",
  ".ps1",
  ".lua",
  ".swift",
  ".kt",
  ".kts",
] as const;
const TEXT_FILE_EXTENSION_SET = new Set<string>(TEXT_FILE_EXTENSIONS);
const TEXT_FILE_ACCEPT = TEXT_FILE_EXTENSIONS.join(",");
const TEXT_FILE_HINT = "支持常见文本格式：TXT / MD / Fountain / FDX / RTF / JSON / CSV / XML / HTML / YAML / LOG / 字幕等";

function loadHistory(): HistoryEntry[] {
  try {
    const raw = localStorage.getItem(HISTORY_KEY);
    return raw ? (JSON.parse(raw) as HistoryEntry[]).sort((a, b) => b.timestamp - a.timestamp) : [];
  } catch { return []; }
}

function saveHistory(entries: HistoryEntry[]) {
  try { localStorage.setItem(HISTORY_KEY, JSON.stringify(entries.sort((a, b) => b.timestamp - a.timestamp).slice(0, 20))); } catch { /* quota exceeded */ }
}

function getFileExtension(filename: string): string {
  const dotIndex = filename.lastIndexOf(".");
  return dotIndex >= 0 ? filename.slice(dotIndex).toLowerCase() : "";
}

function isReadableTextFile(file: File, ext: string): boolean {
  const mime = file.type.toLowerCase();
  return (
    TEXT_FILE_EXTENSION_SET.has(ext) ||
    mime.startsWith("text/") ||
    mime === "application/json" ||
    mime === "application/xml" ||
    mime === "application/xhtml+xml" ||
    mime === "application/x-yaml" ||
    mime === "application/yaml"
  );
}

async function decodeTextFile(file: File): Promise<string> {
  const bytes = await file.arrayBuffer();
  const utf8 = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
  if (!utf8.includes("\uFFFD")) return utf8;

  try {
    return new TextDecoder("gb18030", { fatal: false }).decode(bytes);
  } catch {
    return utf8;
  }
}

function normalizeUploadedText(raw: string, ext: string): string {
  if (ext === ".rtf") {
    const text = raw
      .replace(/\\par[d]?/gi, "\n")
      .replace(/\\line/gi, "\n")
      .replace(/\\'[0-9a-f]{2}/gi, "")
      .replace(/\\[a-z]+\d* ?/gi, "")
      .replace(/[{}]/g, "")
      .replace(/\n{3,}/g, "\n\n")
      .trim();
    return text || raw;
  }

  if ([".html", ".htm", ".xml", ".fdx"].includes(ext) && typeof DOMParser !== "undefined") {
    try {
      const doc = new DOMParser().parseFromString(raw, ext === ".html" || ext === ".htm" ? "text/html" : "application/xml");
      const text = doc.documentElement.textContent?.replace(/\n{3,}/g, "\n\n").trim();
      return text || raw;
    } catch {
      return raw;
    }
  }

  return raw;
}

const SCORE_DIMENSIONS: ScoreDimension[] = [
  { key: "hook", label: "钩子设计", maxScore: 20, hint: "开篇吸引力·悬念设置·黄金三秒", detail: "开篇即抛出高概念钩子，悬念设置紧凑有力。" },
  { key: "character", label: "角色塑造", maxScore: 15, hint: "人物立体度·动机合理性·弧光设计", detail: "主角动机有铺垫，配角功能性较强，人物弧光尚可进一步深化。" },
  { key: "plot", label: "剧情结构", maxScore: 20, hint: "起承转合·节奏把控·冲突设计", detail: "起承转合完整，节奏把控稳健，冲突设计有张力。" },
  { key: "logic", label: "逻辑严密", maxScore: 15, hint: "世界观自洽·伏笔回收·因果链", detail: "世界观整体自洽，伏笔设置到位。" },
  { key: "visual", label: "场景构建", maxScore: 15, hint: "空间描写·视听语言·画面想象力", detail: "视觉意象统一而强烈，场景描写极具画面感。" },
  { key: "content", label: "内容深度", maxScore: 15, hint: "主题表达·情感共鸣·思想内核", detail: "核心设定将科技伦理与人性困境紧密结合，主题表达深刻有力。" },
];

function formatReportMarkdown(result: EvalResult, script: string): string {
  const lines: string[] = [];
  lines.push(`# 剧本评测报告`);
  lines.push("");
  lines.push(`**综合评分**: ${result.totalScore} / 100 · ${result.grade} 级`);
  lines.push("");
  lines.push(`## 概要`);
  lines.push(result.summary);
  lines.push("");
  lines.push(`## 六维评分`);
  for (const dim of SCORE_DIMENSIONS) {
    const score = result.dimensionScores[dim.key] ?? 0;
    const pct = Math.round((score / dim.maxScore) * 100);
    lines.push(`- **${dim.label}**: ${score}/${dim.maxScore} (${pct}%) — ${dim.hint}`);
  }
  if (result.highlights.length > 0) {
    lines.push("");
    lines.push(`## 亮点`);
    result.highlights.forEach((h) => lines.push(`- ${h}`));
  }
  if (result.issues.length > 0) {
    lines.push("");
    lines.push(`## 扣分点`);
    result.issues.forEach((i) => lines.push(`- ${i}`));
  }
  if (result.suggestions.length > 0) {
    lines.push("");
    lines.push(`## 优化建议`);
    result.suggestions.forEach((s) => lines.push(`- ${s}`));
  }
  lines.push("");
  lines.push(`---`);
  lines.push(`*评测时间: ${new Date().toLocaleString("zh-CN")}*`);
  return lines.join("\n");
}

function ScriptTokensPage() {
  const [script, setScript] = useState("");
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<EvalResult | null>(null);
  const [evalError, setEvalError] = useState<string | null>(null);
  const [uploadedFile, setUploadedFile] = useState<{ name: string; size: number } | null>(null);
  const [copied, setCopied] = useState(false);
  const [activeDim, setActiveDim] = useState<number | null>(null);
  const [animatedScore, setAnimatedScore] = useState(0);
  const [history, setHistory] = useState<HistoryEntry[]>(loadHistory);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const scoreFrameRef = useRef<number | null>(null);

  const session = useSessionStore((s) => s.session);
  const hasContent = Boolean(script.trim());

  // Score animation
  useEffect(() => {
    if (!result) return;
    const start = performance.now();
    const target = result.totalScore;
    const dur = 1400;
    function tick(now: number) {
      const t = Math.min((now - start) / dur, 1);
      const e = 1 - Math.pow(1 - t, 3);
      setAnimatedScore(Math.round(e * target));
      if (t < 1) scoreFrameRef.current = requestAnimationFrame(tick);
    }
    scoreFrameRef.current = requestAnimationFrame(tick);
    return () => { if (scoreFrameRef.current) cancelAnimationFrame(scoreFrameRef.current); };
  }, [result]);

  const handleFileUpload = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;
    const ext = getFileExtension(file.name);
    const readable = isReadableTextFile(file, ext);
    setUploadedFile({ name: file.name, size: file.size });
    if (readable) {
      const text = normalizeUploadedText(await decodeTextFile(file), ext);
      setScript(text);
    } else {
      setScript(`[已上传文件：${file.name}]\n\n暂不支持解析 ${ext ? ext.toUpperCase() : "未知"} 格式，请上传常见文本类文件。`);
    }
    event.target.value = "";
  };

  const handleEvaluate = async () => {
    if (!hasContent) return;
    setLoading(true);
    setResult(null);
    setEvalError(null);
    setAnimatedScore(0);
    setActiveDim(null);
    try {
      const aiResult = await evaluateScript(script);
      setResult(aiResult);
      const g = getGrade(aiResult.totalScore);
      const entry: HistoryEntry = {
        name: uploadedFile?.name?.replace(/\.[^.]+$/, "") ?? `剧本 ${new Date().toLocaleDateString("zh-CN")}`,
        date: new Date().toLocaleDateString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }),
        timestamp: Date.now(),
        score: aiResult.totalScore,
        grade: g,
      };
      const updated = [entry, ...loadHistory().filter((h) => h.name !== entry.name || h.score !== entry.score)].sort(
        (a, b) => b.timestamp - a.timestamp,
      );
      saveHistory(updated);
      setHistory(updated);
    } catch (err) {
      setEvalError(err instanceof Error ? err.message : "评测服务暂时不可用，请稍后重试");
    }
    setLoading(false);
  };

  const handleReset = () => {
    setScript("");
    setResult(null);
    setEvalError(null);
    setUploadedFile(null);
    setCopied(false);
    setAnimatedScore(0);
    setActiveDim(null);
    if (fileInputRef.current) fileInputRef.current.value = "";
  };

  const handleCopyReport = async () => {
    if (!result) return;
    const text = formatReportMarkdown(result, script);
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      const ta = document.createElement("textarea");
      ta.value = text;
      ta.style.position = "fixed";
      ta.style.opacity = "0";
      document.body.appendChild(ta);
      ta.select();
      document.execCommand("copy");
      document.body.removeChild(ta);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  };

  const handleExportMarkdown = () => {
    if (!result) return;
    const md = formatReportMarkdown(result, script);
    const blob = new Blob([md], { type: "text/markdown;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `剧本评测_${result.grade}级_${result.totalScore}分_${new Date().toISOString().slice(0, 10)}.md`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  const uploadKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
    if (event.key !== "Enter" && event.key !== " ") return;
    event.preventDefault();
    fileInputRef.current?.click();
  };

  const grade = result ? getGrade(result.totalScore) : null;
  const beatPct = result ? (result.totalScore >= 95 ? 97 : result.totalScore >= 88 ? 92 : result.totalScore >= 80 ? 85 : 72) : 0;
  const compactTitle = uploadedFile?.name?.replace(/\.[^.]+$/, "") ?? "剧本评测";
  const scriptMinutes = Math.max(8, Math.round(script.length / 460));
  const reportDate = new Date().toLocaleDateString("zh-CN", { month: "2-digit", day: "2-digit" });

  return (
    <section className="script-eval-v5 page-motion">
      <div className="script-eval-v5-page">
        {/* Left Panel */}
        <aside className="script-eval-v5-left">
          <div className="script-eval-v5-lp-section">
            <div className="script-eval-v5-lp-label">上传剧本</div>
            <div
              className="script-eval-v5-upload-zone"
              role="button"
              tabIndex={0}
              onClick={() => fileInputRef.current?.click()}
              onKeyDown={uploadKeyDown}
            >
              {uploadedFile ? (
                <div className="script-eval-v5-upload-done is-show">
                  <CheckCircleFilled />
                  <span className="script-eval-v5-uf-name">{uploadedFile.name}</span>
                  <span className="script-eval-v5-uf-re" onClick={(e) => { e.stopPropagation(); handleReset(); }}>
                    重新上传
                  </span>
                </div>
              ) : (
                <>
                  <div className="script-eval-v5-upload-icon"><UploadOutlined /></div>
                  <div className="script-eval-v5-upload-text">拖拽或点击上传</div>
                  <button type="button" className="script-eval-v5-upload-btn" onClick={(e) => { e.stopPropagation(); fileInputRef.current?.click(); }}>
                    + 上传剧本
                  </button>
                  <div className="script-eval-v5-upload-hint">{TEXT_FILE_HINT}</div>
                </>
              )}
            </div>
            <input ref={fileInputRef} type="file" accept={TEXT_FILE_ACCEPT} style={{ display: "none" }} onChange={handleFileUpload} />
          </div>

          <div className="script-eval-v5-lp-section">
            <div className="script-eval-v5-lp-label">AI 识别信息</div>
            <div className="script-eval-v5-info-grid">
              {!result ? (
                <div className="script-eval-v5-info-empty">上传剧本并点击评测后识别</div>
              ) : (
                <>
                  <div className="script-eval-v5-info-item">
                    <span className="script-eval-v5-info-key">综合评分</span>
                    <span className="script-eval-v5-info-val"><span className="script-eval-v5-info-tag">{result.totalScore}分 · {grade}级</span></span>
                  </div>
                  <div className="script-eval-v5-info-item">
                    <span className="script-eval-v5-info-key">文本长度</span>
                    <span className="script-eval-v5-info-val">{script.length} 字</span>
                  </div>
                  <div className="script-eval-v5-info-item">
                    <span className="script-eval-v5-info-key">评测时间</span>
                    <span className="script-eval-v5-info-val">{new Date().toLocaleDateString("zh-CN")}</span>
                  </div>
                  <div className="script-eval-v5-info-item">
                    <span className="script-eval-v5-info-key">击败比例</span>
                    <span className="script-eval-v5-info-val">{beatPct}%</span>
                  </div>
                </>
              )}
            </div>
          </div>

          <div className="script-eval-v5-lp-section is-fill">
            <div className="script-eval-v5-lp-label">历史评测</div>
            <div className="script-eval-v5-history-list">
              {!session ? (
                <div className="script-eval-v5-history-empty">登录后查看云端评测记录</div>
              ) : history.length === 0 ? (
                <div className="script-eval-v5-history-empty">暂无评测记录</div>
              ) : (
                history.map((item, i) => (
                  <div key={i} className={`script-eval-v5-history-item${i === 0 ? " is-active" : ""}`}>
                    <div className="script-eval-v5-hi-left">
                      <div className="script-eval-v5-hi-name">{item.name}</div>
                      <div className="script-eval-v5-hi-date">{item.date}</div>
                      <div className="script-eval-v5-hi-bar">
                        <div className="script-eval-v5-hi-bar-fill" style={{ width: `${Math.min(92, (item.score / 100) * 100)}%` }} />
                      </div>
                    </div>
                    <div className="script-eval-v5-hi-right">
                      <div className={`script-eval-v5-hi-score${item.score >= 90 ? " is-green" : ""}`}>{item.score}</div>
                      <div className="script-eval-v5-hi-grade">{item.grade}</div>
                    </div>
                  </div>
                ))
              )}
            </div>
          </div>

          <div className="script-eval-v5-lp-bottom">
            <button
              type="button"
              className="script-eval-v5-eval-btn"
              disabled={loading || !hasContent}
              onClick={() => void handleEvaluate()}
            >
              {loading ? "◆ 评测中..." : "◆ 开始评测"}
            </button>
            <button type="button" className="script-eval-v5-export-btn" disabled={!result} onClick={handleExportMarkdown}>
              导出评测报告
            </button>
          </div>
        </aside>

        {/* Right Area */}
        <div className="script-eval-v5-right">
          <div className="script-eval-v5-right-topbar">
            <div className="script-eval-v5-right-title">
              <span className="script-eval-v5-rt-green">剧本评测</span>
              {uploadedFile && <> · {compactTitle}</>}
            </div>
            <div className="script-eval-v5-right-actions">
              {result && (
                <>
                  <button type="button" className="script-eval-v5-action-btn" onClick={() => void handleCopyReport()}>
                    <CopyOutlined />{copied ? "已复制" : "复制"}
                  </button>
                  <button type="button" className="script-eval-v5-action-btn" onClick={handleExportMarkdown}>
                    <DownloadOutlined />导出
                  </button>
                </>
              )}
            </div>
          </div>

          <div className={`script-eval-v5-right-content${result ? " is-report" : ""}`}>
            {!result && (
              <div className="script-eval-v5-input-section">
                <div className="script-eval-v5-illustration" aria-label="上传剧本并开始评测">
                  <div
                    className="script-eval-v5-illustration-hit"
                    role="button"
                    tabIndex={0}
                    onClick={() => fileInputRef.current?.click()}
                    onKeyDown={uploadKeyDown}
                  >
                    <div className="script-eval-v5-upload-card-icon">
                      <FileTextOutlined />
                    </div>
                    <div className="script-eval-v5-upload-card-title">
                      {uploadedFile ? "剧本已导入" : "上传剧本文件"}
                    </div>
                    <div className="script-eval-v5-upload-card-desc">
                      {uploadedFile
                        ? "如需更换，点击此处重新上传；完成后点击左侧开始评测。"
                        : `${TEXT_FILE_HINT}，上传后点击开始评测，AI 将识别剧本信息。`}
                    </div>
                  </div>
                </div>

                {evalError && (
                  <div className="script-eval-v5-error" role="alert">
                    <span>⚠</span><span>{evalError}</span>
                  </div>
                )}
              </div>
            )}

            {result && (
              <section className="script-eval-report script-eval-report--inside">
                <div className="script-eval-report__body">
                  <header className="script-eval-report__hero">
                    <div className="script-eval-report__score-block">
                      <div className="script-eval-report__score-row">
                        <span className="script-eval-report__score">{animatedScore}</span>
                        <span className="script-eval-report__score-total">/ 100</span>
                        <span className="script-eval-report__grade">
                          <i />
                          {grade}级
                        </span>
                      </div>
                      <div className="script-eval-report__score-line">
                        <span style={{ width: `${animatedScore}%` }} />
                      </div>
                      <div className="script-eval-report__beat">击败全国 <b>{beatPct}%</b> 剧本</div>
                    </div>

                    <div className="script-eval-report__summary">
                      <div className="script-eval-report__title-line">
                        <div>
                          <h1>{compactTitle}</h1>
                          <p>{`剧本评测 · ${scriptMinutes} min · ${reportDate}`}</p>
                        </div>
                      </div>
                      <p className="script-eval-report__desc">{result.summary}</p>
                    </div>
                  </header>

                  <section className="script-eval-report__chart-card" aria-label="维度拆解">
                    <div className="script-eval-report__card-head">
                      <span><i />维度拆解</span>
                      <div className="script-eval-report__legend">
                        <span><i className="is-score" />得分</span>
                        <span><i className="is-loss" />扣分</span>
                      </div>
                    </div>
                    <div className="script-eval-report__chart">
                      <div className="script-eval-report__axis">
                        <span>100%</span>
                        <span>80%</span>
                        <span>60%</span>
                        <span>40%</span>
                        <span>20%</span>
                        <span>0%</span>
                      </div>
                      <div className="script-eval-report__chart-grid">
                        {SCORE_DIMENSIONS.map((dim) => {
                          const score = result.dimensionScores[dim.key] ?? 0;
                          const pct = Math.max(0, Math.min(1, score / dim.maxScore));
                          const lossPct = 1 - pct;
                          const isPerfect = score === dim.maxScore;
                          return (
                            <button key={dim.key} type="button" className="script-eval-report__bar-col">
                              <div className="script-eval-report__bar-score">
                                <b>{score}</b><small>/{dim.maxScore}</small>{isPerfect ? <em>*</em> : null}
                              </div>
                              <div className="script-eval-report__bar-box">
                                {lossPct > 0 ? <div className="script-eval-report__bar-loss" style={{ height: `${lossPct * 100}%` }} /> : null}
                                <div className="script-eval-report__bar-fill" style={{ height: `${pct * 100}%` }} />
                              </div>
                              <strong>{dim.label}</strong>
                              <span>{dim.hint}</span>
                            </button>
                          );
                        })}
                      </div>
                    </div>
                  </section>

                  <div className="script-eval-report__findings">
                    {result.highlights.length > 0 ? (
                      <section className="script-eval-report__finding-group is-highlight">
                        <h2>亮点 <span>{result.highlights.length}</span></h2>
                        <div>
                          {result.highlights.map((item, index) => (
                            <p key={index}>{item}</p>
                          ))}
                        </div>
                      </section>
                    ) : null}
                    {result.issues.length > 0 ? (
                      <section className="script-eval-report__finding-group is-issue">
                        <h2>扣分点 <span>{result.issues.length}</span></h2>
                        <div>
                          {result.issues.map((item, index) => (
                            <p key={index}>{item}</p>
                          ))}
                        </div>
                      </section>
                    ) : null}
                  </div>

                  {result.suggestions.length > 0 ? (
                    <section className="script-eval-report__path-card">
                      <div className="script-eval-report__card-head">
                        <span><i />优化路径</span>
                      </div>
                      <table className="script-eval-report__path-table">
                        <thead>
                          <tr>
                            <th>#</th>
                            <th>类型</th>
                            <th>优化路径</th>
                            <th>优先级</th>
                          </tr>
                        </thead>
                        <tbody>
                          {result.suggestions.map((item, index) => {
                            const high = index < 2;
                            return (
                              <tr key={index}>
                                <td>{String(index + 1).padStart(2, "0")}</td>
                                <td>{high ? "核心" : "增强"}</td>
                                <td>{item}</td>
                                <td><span className={high ? "is-high" : "is-mid"}>{high ? "HIGH" : "MID"}</span></td>
                              </tr>
                            );
                          })}
                        </tbody>
                      </table>
                    </section>
                  ) : null}
                </div>
              </section>
            )}
          </div>

          <div className="script-eval-v5-statusbar">
            <div className="script-eval-v5-status-dot" />
            <span>{loading ? "评测中..." : result ? "评测完成" : hasContent ? "待评测" : "等待上传"}</span>
            <span className="script-eval-v5-sb-right">{result ? `六维标准 · ${result.totalScore}分` : "六维标准"}</span>
          </div>
        </div>
      </div>
    </section>
  );
}

export default ScriptTokensPage;
