import { useCallback, useEffect, useRef, useState, useMemo } from "react";
import { API } from "../config";

/* ─── Types ─── */
type Step = 0 | 1 | 2 | 3 | 4;
type ClarifyMsg = { role: "user" | "assistant"; content: string };

type RequirementAnalysis = {
  summary: string;
  functional_requirements: string[];
  non_functional_requirements: string[];
  acceptance_criteria: string[];
  edge_cases: string[];
};

type TestCase = {
  test_id: string;
  test_name: string;
  precondition: string;
  steps: string[] | string;
  expected_result: string;
  test_type?: string;
};

type CodeGeneration = {
  java_code: string;
  unit_tests: string;
  implementation_notes: string;
};

type TestExecution = {
  success: boolean;
  passed: number;
  failed: number;
  errors: number;
  total: number;
  output: string;
};

/* ─── API helpers ─── */
const BASE = API.devops;

async function apiPost<T = unknown>(path: string, body?: unknown): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    method: "POST",
    headers: body !== undefined ? { "Content-Type": "application/json" } : undefined,
    body: body !== undefined ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
  return res.json();
}

// SSE 格式：data: {"type":"chunk","text":"..."} / {"type":"done",...} / {"type":"error","message":"..."}
async function readSSE(
  path: string,
  onChunk: (text: string) => void,
  onDone?: (data: any) => void,
  signal?: AbortSignal,
) {
  const res = await fetch(`${BASE}${path}`, { signal });
  if (!res.ok) throw new Error(`${res.status}`);
  if (!res.body) return;
  const reader = res.body.getReader();
  const dec = new TextDecoder();
  let buf = "";
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      buf += dec.decode(value, { stream: true });
      const parts = buf.split("\n\n");
      buf = parts.pop() ?? "";
      for (const part of parts) {
        const line = part.trim();
        if (!line.startsWith("data:")) continue;
        const payload = line.slice(5).trim();
        if (payload === "[DONE]") return;
        try {
          const evt = JSON.parse(payload);
          if (evt.type === "chunk" && evt.text) {
            onChunk(evt.text);
          } else if (evt.type === "done") {
            onDone?.(evt);
            return;
          } else if (evt.type === "error") {
            throw new Error(evt.message || "Stream error");
          } else if (evt.text) {
            onChunk(evt.text);
          } else if (evt.message) {
            onChunk(evt.message);
          }
        } catch (e) {
          if (e instanceof Error && !e.message.startsWith("Stream error")) onChunk(payload);
          else throw e;
        }
      }
    }
  } finally {
    reader.releaseLock();
  }
}

/* ── 流式 JSON 增量解析工具 ── */
function parseStreamStr(text: string, fieldName: string): { value: string; active: boolean } {
  const idx = text.indexOf(`"${fieldName}"`);
  if (idx === -1) return { value: "", active: false };
  let start = idx + fieldName.length + 2;
  while (start < text.length && (text[start] === " " || text[start] === ":")) start++;
  if (start >= text.length || text[start] !== '"') return { value: "", active: false };
  start++;
  let value = "", i = start, closed = false;
  while (i < text.length) {
    if (text[i] === "\\" && i + 1 < text.length) {
      const e = text[i + 1];
      value += e === "n" ? "\n" : e === "t" ? "\t" : e;
      i += 2;
    } else if (text[i] === '"') { closed = true; break; }
    else { value += text[i++]; }
  }
  return { value, active: !closed };
}

function parseStreamStrArray(text: string, fieldName: string): { items: { value: string; active: boolean }[]; active: boolean } {
  const idx = text.indexOf(`"${fieldName}"`);
  if (idx === -1) return { items: [], active: false };
  let start = idx + fieldName.length + 2;
  while (start < text.length && (text[start] === " " || text[start] === ":")) start++;
  if (start >= text.length || text[start] !== "[") return { items: [], active: false };
  start++;
  const items: { value: string; active: boolean }[] = [];
  let i = start, arrayClosed = false;
  while (i < text.length) {
    if (text[i] === "]") { arrayClosed = true; break; }
    if (text[i] === '"') {
      i++;
      let value = "", itemClosed = false;
      while (i < text.length) {
        if (text[i] === "\\" && i + 1 < text.length) {
          const e = text[i + 1];
          value += e === "n" ? "\n" : e === "t" ? "\t" : e;
          i += 2;
        } else if (text[i] === '"') { itemClosed = true; i++; break; }
        else { value += text[i++]; }
      }
      if (value.trim()) items.push({ value, active: !itemClosed });
    } else { i++; }
  }
  return { items, active: !arrayClosed };
}

function parseStreamTestCaseNames(text: string): { names: string[]; active: boolean } {
  const idx = text.indexOf('"test_cases"');
  if (idx === -1) return { names: [], active: false };
  let start = idx + 12;
  while (start < text.length && (text[start] === " " || text[start] === ":")) start++;
  if (start >= text.length || text[start] !== "[") return { names: [], active: false };
  let depth = 0, inStr = false, arrayClosed = false;
  for (let i = start; i < text.length; i++) {
    const ch = text[i];
    if (inStr) { if (ch === "\\") i++; else if (ch === '"') inStr = false; }
    else { if (ch === '"') inStr = true; else if (ch === "[") depth++; else if (ch === "]") { depth--; if (depth === 0) { arrayClosed = true; break; } } }
  }
  const arrayText = text.slice(start);
  const names: string[] = [];
  const re = /"test_name"\s*:\s*"((?:[^"\\]|\\.)*)"/g;
  let m: RegExpExecArray | null;
  while ((m = re.exec(arrayText)) !== null) {
    names.push(m[1].replace(/\\n/g, " ").replace(/\\"/g, '"'));
  }
  return { names, active: !arrayClosed };
}

type DevStreamResult = { java_code: string; unit_tests: string; implementation_notes: string; currentField: string | null };

function parseDevStream(text: string): DevStreamResult {
  const result: DevStreamResult = {
    java_code: "", unit_tests: "", implementation_notes: "", currentField: null,
  };
  for (const field of ["java_code", "unit_tests", "implementation_notes" ] as const) {
    const key = `"${field}"`;
    const idx = text.indexOf(key);
    if (idx === -1) continue;
    let start = idx + key.length;
    while (start < text.length && (text[start] === " " || text[start] === ":")) start++;
    if (start >= text.length || text[start] !== '"') continue;
    start++;
    let value = "", i = start, closed = false;
    while (i < text.length) {
      if (text[i] === "\\" && i + 1 < text.length) {
        const e = text[i + 1];
        value += e === "n" ? "\n" : e === "t" ? "\t" : e;
        i += 2;
      } else if (text[i] === '"') { closed = true; break; }
      else { value += text[i++]; }
    }
    result[field] = value;
    if (!closed) result.currentField = field;
  }
  return result;
}

/* ── 步骤标签 ── */
const STEPS = [
  { title: "Requirements", icon: "💬" },
  { title: "PM Analysis", icon: "📋" },
  { title: "QA Cases", icon: "🧪" },
  { title: "Dev Code", icon: "💻" },
  { title: "Test Run", icon: "▶" },
];

const STATUS_STEP: Record<string, number> = {
  clarifying: 0, pm_ready: 0,
  pm_done: 1, qa_ready: 1,
  qa_done: 2, dev_ready: 2,
  dev_done: 3, test_done: 4,
};

const STATUS_LABEL: Record<string, string> = {
  clarifying: "Clarifying", pm_ready: "Ready",
  pm_done: "PM Done", qa_ready: "PM Done",
  qa_done: "QA Done", dev_ready: "QA Done",
  dev_done: "Code Ready", test_done: "Tests Done",
};

const TYPE_EMOJI: Record<string, string> = {
  "Functional": "🧩", "Performance": "⚡", "Security": "🔒",
  "功能测试": "🧩", "性能测试": "⚡", "安全测试": "🔒",
};

const TYPE_LABEL: Record<string, string> = {
  "功能测试": "Functional", "性能测试": "Performance",
  "安全测试": "Security", "边界测试": "Boundary",
  "异常测试": "Exception", "集成测试": "Integration",
};

/* ━━━━━━━━━━━━━━━━━━━━━ Component ━━━━━━━━━━━━━━━━━━━━━ */
export default function DevOpsAgent() {
  const [step, setStep] = useState<Step>(0);
  const [sessionId, setSessionId] = useState("");
  const [status, setStatus] = useState("");
  const [loading, setLoading] = useState(false);
  const [streaming, setStreaming] = useState(false);
  const [error, setError] = useState("");
  const [streamText, setStreamText] = useState("");

  // Step 0
  const [requirement, setRequirement] = useState("");
  const [rawRequirement, setRawRequirement] = useState("");
  const [clarifyHistory, setClarifyHistory] = useState<ClarifyMsg[]>([]);
  const [clarifyInput, setClarifyInput] = useState("");

  // Step 1
  const [requirementAnalysis, setRequirementAnalysis] = useState<RequirementAnalysis | null>(null);
  const [pmFeedback, setPmFeedback] = useState("");

  // Step 2
  const [testCases, setTestCases] = useState<TestCase[]>([]);
  const [testStrategy, setTestStrategy] = useState("");
  const [coveragePlan, setCoveragePlan] = useState("");
  const [qaFeedback, setQaFeedback] = useState("");

  // Step 3
  const [codeGeneration, setCodeGeneration] = useState<CodeGeneration | null>(null);
  const [codeTab, setCodeTab] = useState<"java_code" | "unit_tests" | "implementation_notes">("java_code");
  const [devStreamTab, setDevStreamTab] = useState<"java_code" | "unit_tests" | "implementation_notes">("java_code");

  // Step 4
  const [testExecution, setTestExecution] = useState<TestExecution | null>(null);

  const abortRef = useRef<AbortController | null>(null);
  const bottomRef = useRef<HTMLDivElement>(null);
  const pmStreamRef = useRef<HTMLDivElement>(null);
  const qaStreamRef = useRef<HTMLDivElement>(null);
  const devStreamRef = useRef<HTMLPreElement>(null);

  /* ── 流式增量解析 ── */
  const pmStreamParsed = useMemo(() => {
    if (!streaming || step !== 1) return null;
    const t = streamText;
    const fr = parseStreamStrArray(t, "functional_requirements");
    const nfr = parseStreamStrArray(t, "non_functional_requirements");
    const ac = parseStreamStrArray(t, "acceptance_criteria");
    const ec = parseStreamStrArray(t, "edge_cases");
    const sum = parseStreamStr(t, "summary");
    let currentSection: string | null = null;
    for (const [key, val] of [["functional_requirements", fr], ["non_functional_requirements", nfr], ["acceptance_criteria", ac], ["edge_cases", ec]] as const) {
      if (val.active || val.items.some((i) => i.active)) { currentSection = key; break; }
    }
    if (!currentSection && sum.active) currentSection = "summary";
    return { functional_requirements: fr, non_functional_requirements: nfr, acceptance_criteria: ac, edge_cases: ec, summary: sum, currentSection };
  }, [streaming, step, streamText]);

  const qaStreamParsed = useMemo(() => {
    if (!streaming || step !== 2) return null;
    const t = streamText;
    const cases = parseStreamTestCaseNames(t);
    const strategy = parseStreamStr(t, "test_strategy");
    const coverage = parseStreamStr(t, "coverage_plan");
    let currentSection: string | null = null;
    if (cases.active) currentSection = "test_cases";
    else if (strategy.active) currentSection = "test_strategy";
    else if (coverage.active) currentSection = "coverage_plan";
    else if (cases.names.length) currentSection = "test_cases";
    return { testCases: cases, testStrategy: strategy, coveragePlan: coverage, currentSection };
  }, [streaming, step, streamText]);

  const devStreamParsed = useMemo(() => {
    if (!streaming || step !== 3) return null;
    return parseDevStream(streamText);
  }, [streaming, step, streamText]);

  // Dev 流式时自动切换 Tab
  useEffect(() => {
    if (devStreamParsed?.currentField) {
      const f = devStreamParsed.currentField as typeof devStreamTab;
      if (["java_code", "unit_tests", "implementation_notes"].includes(f)) setDevStreamTab(f);
    }
  }, [devStreamParsed?.currentField]);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" });
    // 同时滚动各流式容器到底部
    if (pmStreamRef.current) pmStreamRef.current.scrollTop = pmStreamRef.current.scrollHeight;
    if (qaStreamRef.current) qaStreamRef.current.scrollTop = qaStreamRef.current.scrollHeight;
    if (devStreamRef.current) devStreamRef.current.scrollTop = devStreamRef.current.scrollHeight;
  }, [streamText]);

  useEffect(() => {
    return () => abortRef.current?.abort();
  }, []);

  function applySessionData(data: any) {
    if (data.status) setStatus(data.status);
    if (data.data?.requirement_analysis) setRequirementAnalysis(data.data.requirement_analysis);
    if (data.data?.test_cases) {
      const tc = data.data.test_cases;
      if (tc.test_cases?.length) setTestCases(tc.test_cases);
      if (tc.test_strategy) setTestStrategy(tc.test_strategy);
      if (tc.coverage_plan) setCoveragePlan(tc.coverage_plan);
    }
    if (data.data?.code_generation) setCodeGeneration(data.data.code_generation);
    if (data.data?.test_execution) setTestExecution(data.data.test_execution);
  }

  /* ── 流式通用封装 ── */
  const withStreaming = useCallback(async (
    streamPath: string,
    targetStep: Step,
    runPath?: string,
  ) => {
    setStreamText("");
    setStreaming(true);
    setStep(targetStep);
    setError("");
    if (targetStep === 3) setDevStreamTab("java_code");
    try {
      if (runPath) await apiPost(runPath);
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      await readSSE(
        streamPath,
        (text) => setStreamText((prev) => prev + text),
        (doneData) => applySessionData(doneData),
        ctrl.signal,
      );
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setStreaming(false);
    }
  }, []);

  /* ── Step 0: 创建会话 ── */
  const handleStart = useCallback(async () => {
    if (!requirement.trim() || loading) return;
    setLoading(true);
    setError("");
    try {
      const data: any = await apiPost("/session/start", { requirement: requirement.trim() });
      setSessionId(data.session_id);
      setRawRequirement(requirement.trim());
      setStatus(data.status || "clarifying");
      const q = data.clarify_questions || data.question;
      if (q) setClarifyHistory([{ role: "assistant", content: q }]);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [requirement, loading]);

  /* ── Step 0: 需求澄清 ── */
  const handleClarify = useCallback(async () => {
    if (!clarifyInput.trim() || loading) return;
    const msg = clarifyInput.trim();
    setClarifyHistory((h) => [...h, { role: "user", content: msg }]);
    setClarifyInput("");
    setLoading(true);
    setError("");
    try {
      const data: any = await apiPost(`/session/${sessionId}/clarify`, { message: msg });
      setStatus(data.status || status);
      const q = data.clarify_questions || data.question;
      if (q) setClarifyHistory((h) => [...h, { role: "assistant", content: q }]);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [clarifyInput, sessionId, loading, status]);

  const handlePmRun = useCallback(() =>
    withStreaming(`/session/${sessionId}/pm/stream`, 1),
    [sessionId, withStreaming]);

  const handlePmRefine = useCallback(async () => {
    if (!pmFeedback.trim()) return;
    const fb = pmFeedback.trim();
    setPmFeedback("");
    await withStreaming(`/session/${sessionId}/pm/refine/stream?feedback=${encodeURIComponent(fb)}`, 1);
  }, [sessionId, pmFeedback, withStreaming]);

  const handleQaRun = useCallback(() =>
    withStreaming(`/session/${sessionId}/qa/stream`, 2),
    [sessionId, withStreaming]);

  const handleQaRefine = useCallback(async () => {
    if (!qaFeedback.trim()) return;
    const fb = qaFeedback.trim();
    setQaFeedback("");
    await withStreaming(`/session/${sessionId}/qa/refine/stream?feedback=${encodeURIComponent(fb)}`, 2);
  }, [sessionId, qaFeedback, withStreaming]);

  const handleDevRun = useCallback(() =>
    withStreaming(`/session/${sessionId}/dev/stream`, 3),
    [sessionId, withStreaming]);

  /* ── Step 4: 测试执行 ── */
  const handleTestRun = useCallback(async () => {
    setStep(4);
    setLoading(true);
    setError("");
    try {
      const data: any = await apiPost(`/session/${sessionId}/test/run`);
      const te = data?.data?.test_execution ?? data;
      setTestExecution({
        success: te.success ?? ((te.failed ?? 0) === 0 && (te.errors ?? 0) === 0),
        passed: te.passed ?? 0,
        failed: te.failed ?? 0,
        errors: te.errors ?? 0,
        total: te.total ?? 0,
        output: te.output || data.detail || JSON.stringify(data, null, 2),
      });
      if (data.status) setStatus(data.status);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId]);

  /* ── AI 自动修复 ── */
  const handleTestFix = useCallback(async () => {
    setTestExecution(null);
    await withStreaming(`/session/${sessionId}/test/fix/stream`, 3);
    await handleTestRun();
  }, [sessionId, withStreaming, handleTestRun]);

  /* ── 用例分组 ── */
  const groupedTestCases = useMemo(() => {
    const groups: Record<string, TestCase[]> = {};
    for (const tc of testCases) {
      const t = tc.test_type || "Functional";
      if (!groups[t]) groups[t] = [];
      groups[t].push(tc);
    }
    return groups;
  }, [testCases]);

  function parseNotes(text: string): string[] {
    if (!text) return [];
    return text.split("\n").map((l) => l.replace(/^\d+\.\s*/, "").trim()).filter((l) => l.length > 0);
  }

  const currentStep = STATUS_STEP[status] ?? step;
  const statusLabel = STATUS_LABEL[status] || status;

  return (
    <div className="flex flex-col h-full overflow-hidden bg-[#f7f7f9]">
      {/* ── 步骤栏 ── */}
      <div className="shrink-0 border-b border-border bg-white shadow-[0_1px_8px_rgba(0,0,0,0.04)]">
        <div className="flex items-center gap-0 px-[60px] py-0">
          {STEPS.map((s, i) => (
            <div key={i} className="flex items-center">
              <button
                onClick={() => { if (sessionId && i <= step) setStep(i as Step); }}
                className={`flex items-center gap-2.5 px-5 py-4 text-sm font-semibold border-b-2 transition-all duration-200 ${
                  i === step
                    ? "border-magenta text-magenta"
                    : i < step
                      ? "border-transparent text-green-600"
                      : "border-transparent text-txt-muted"
                } ${i <= step ? "cursor-pointer" : "cursor-default"}`}
              >
                <span className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold shrink-0 transition-colors ${
                  i === step
                    ? "bg-magenta text-white"
                    : i < step
                      ? "bg-green-500 text-white"
                      : "bg-gray-200 text-gray-400"
                }`}>
                  {i < step ? "✓" : i + 1}
                </span>
                <span className="hidden sm:block">{s.title}</span>
              </button>
              {i < STEPS.length - 1 && (
                <span className={`mx-1 text-sm ${ i < step ? "text-green-400" : "text-gray-300" }`}>›</span>
              )}
            </div>
          ))}
          {sessionId && statusLabel && (
            <div className={`ml-auto mr-2 px-3 py-1 text-xs font-bold rounded-full ${
              status === "clarifying" ? "bg-amber-50 text-amber-600 border border-amber-200" :
              status === "test_done" ? "bg-green-50 text-green-600 border border-green-200" :
              "bg-magenta-50 text-magenta border border-magenta/20"
            }`}>
              {statusLabel}
            </div>
          )}
        </div>
      </div>

      {/* Error */}
      {error && (
        <div className="flex items-center justify-between px-4 py-2.5 mx-10 mt-4 text-sm text-red-700 bg-red-50 border border-red-200 rounded-xl">
          <span className="flex items-center gap-2"><span>⚠️</span>{error}</span>
          <button className="ml-4 font-bold text-red-300 hover:text-red-500" onClick={() => setError("")}>✕</button>
        </div>
      )}

      {/* ── 内容区 ── */}
      <div className="flex-1 px-[60px] py-6 overflow-y-auto">
        <div className="space-y-0">

          {/* ═══ Step 0: Requirement Input ═══ */}
          {step === 0 && !sessionId && (
            <div className="card">
              <div className="flex items-start gap-4 mb-6">
                <div className="flex items-center justify-center w-10 h-10 text-xl rounded-2xl bg-magenta/10 shrink-0">📋</div>
                <div>
                  <h2 className="text-base font-bold text-txt mb-0.5">Enter Requirements</h2>
                  <p className="text-sm text-txt-muted">Describe your product requirements. AI will complete analysis → test cases → code generation automatically.</p>
                </div>
              </div>
              <textarea
                className="input-field min-h-[160px] resize-y mb-5"
                value={requirement}
                onChange={(e) => setRequirement(e.target.value)}
                placeholder="e.g. Implement a user login feature supporting username/password, log all login events, target 1000 QPS concurrency…"
              />
              <div className="flex items-center justify-between">
                <span className="text-xs text-txt-muted">{requirement.length > 0 ? `${requirement.length} chars` : ""}</span>
                <button className="btn-magenta" onClick={handleStart} disabled={loading || !requirement.trim()}>
                  {loading ? (
                    <span className="flex items-center gap-2"><span className="w-3.5 h-3.5 border-2 border-white/40 border-t-white rounded-full animate-spin inline-block"></span>Analyzing…</span>
                  ) : "Start AI Analysis →"}
                </button>
              </div>
            </div>
          )}

          {/* ═══ Step 0: Clarification ═══ */}
          {step === 0 && sessionId && (
            <div className="card">
              <div className="flex items-center gap-3 mb-5">
                <div className="flex items-center justify-center w-8 h-8 text-base rounded-xl bg-magenta/10">💬</div>
                <h2 className="text-base font-bold">Requirement Clarification</h2>
              </div>

              <div className="p-4 mb-5 text-sm bg-[#f9f9f9] border border-border rounded-xl">
                <span className="block mb-1.5 text-[11px] font-bold text-txt-muted uppercase tracking-wide">Original Requirement</span>
                <p className="leading-relaxed text-txt">{rawRequirement}</p>
              </div>

              {clarifyHistory.length > 0 && (
                <div className="flex flex-col gap-3 mb-5">
                  {clarifyHistory.map((msg, i) => (
                    <div
                      key={i}
                      className={`max-w-[85%] px-4 py-3 text-sm rounded-2xl ${
                        msg.role === "user"
                          ? "self-end bg-gray-100 text-txt"
                          : "self-start bg-white border border-border shadow-sm"
                      }`}
                    >
                      <span className="block mb-1 text-[11px] font-bold text-txt-muted">
                        {msg.role === "assistant" ? "🤖 AI Assistant" : "👤 You"}
                      </span>
                      <span className="leading-relaxed whitespace-pre-wrap">{msg.content}</span>
                    </div>
                  ))}
                </div>
              )}

              {status === "clarifying" && (
                <div className="pt-4 mt-2 border-t border-border">
                  <p className="mb-2 text-xs font-semibold tracking-wide uppercase text-txt-muted">Reply to AI</p>
                  <textarea
                    className="input-field min-h-[80px] resize-y mb-3"
                    value={clarifyInput}
                    onChange={(e) => setClarifyInput(e.target.value)}
                    placeholder="Enter your additional details…"
                    disabled={loading}
                  />
                  <div className="flex justify-end">
                    <button className="btn-magenta" onClick={handleClarify} disabled={loading}>
                      {loading ? <span className="flex items-center gap-2"><span className="w-3.5 h-3.5 border-2 border-white/40 border-t-white rounded-full animate-spin inline-block"></span>Sending…</span> : "Send"}
                    </button>
                  </div>
                </div>
              )}

              {status !== "clarifying" && status !== "" && (
                <div className="pt-4 mt-2 border-t border-border">
                  <div className="flex items-center gap-2 px-4 py-3 mb-4 text-sm text-green-700 border border-green-200 bg-green-50 rounded-xl">
                    <span>✅</span><span>Requirements confirmed. Ready to start PM analysis.</span>
                  </div>
                  <div className="flex justify-end">
                    <button className="btn-magenta" onClick={handlePmRun} disabled={loading || streaming}>
                      {loading ? "Analyzing…" : "Start PM Analysis →"}
                    </button>
                  </div>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 1: PM Analysis ═══ */}
          {step === 1 && (
            <div className="card">
              <div className="flex items-center justify-between mb-5">
                <div className="flex items-center gap-3">
                  <div className="flex items-center justify-center w-8 h-8 text-base rounded-xl bg-orange-50">📋</div>
                  <h2 className="text-base font-bold">PM Analysis</h2>
                </div>
                {streaming && (
                  <span className="flex items-center gap-1.5 text-xs font-semibold text-magenta bg-magenta/5 px-3 py-1 rounded-full">
                    <span className="w-1.5 h-1.5 bg-magenta rounded-full animate-pulse inline-block"></span>
                    Analyzing… {streamText.length} chars
                  </span>
                )}
              </div>

              {/* Streaming preview */}
              {streaming && pmStreamParsed && (
                <div ref={pmStreamRef} className="rounded-xl border border-border bg-[#fafafa] p-4 mb-4 space-y-3 max-h-[55vh] overflow-y-auto">
                  {([
                    ["functional_requirements", "🔧", "Functional Requirements", "bg-blue-50 text-blue-700"],
                    ["non_functional_requirements", "⚙️", "Non-Functional Requirements", "bg-purple-50 text-purple-700"],
                    ["acceptance_criteria", "✅", "Acceptance Criteria", "bg-green-50 text-green-700"],
                    ["edge_cases", "🚧", "Edge Cases", "bg-amber-50 text-amber-700"],
                  ] as const).map(([key, icon, label, color]) => {
                    const sec = pmStreamParsed[key];
                    if (!sec.items.length && pmStreamParsed.currentSection !== key) return null;
                    return (
                      <div key={key} className={`transition-opacity ${ pmStreamParsed.currentSection === key ? "opacity-100" : "opacity-50" }`}>
                        <div className={`inline-flex items-center gap-1 text-[11px] font-bold px-2 py-0.5 rounded-md mb-2 ${color}`}>{icon} {label}</div>
                        <ul className="pl-1 space-y-1">
                          {sec.items.map((item, i) => (
                            <li key={i} className="flex items-start gap-2 text-sm">
                              <span className="mt-1.5 w-1 h-1 rounded-full bg-current shrink-0 opacity-40"></span>
                              <span>{item.value}{item.active && <span className="text-magenta animate-pulse ml-0.5">|</span>}</span>
                            </li>
                          ))}
                        </ul>
                      </div>
                    );
                  })}
                  {(pmStreamParsed.summary.value || pmStreamParsed.currentSection === "summary") && (
                    <div className={`transition-opacity ${ pmStreamParsed.currentSection === "summary" ? "opacity-100" : "opacity-50" }`}>
                      <div className="inline-flex items-center gap-1 text-[11px] font-bold px-2 py-0.5 rounded-md mb-2 bg-gray-100 text-gray-600">📌 Summary</div>
                      <p className="text-sm leading-relaxed">{pmStreamParsed.summary.value}{pmStreamParsed.summary.active && <span className="text-magenta animate-pulse">|</span>}</p>
                    </div>
                  )}
                  {!pmStreamParsed.currentSection && (
                    <div className="flex items-center justify-center gap-2 py-4 text-sm text-txt-muted">
                      <span className="inline-block w-4 h-4 border-2 rounded-full border-magenta/30 border-t-magenta animate-spin"></span>
                      Waiting for AI output…
                    </div>
                  )}
                </div>
              )}

              {/* Final result — clean list layout */}
              {!streaming && requirementAnalysis && (
                <div className="mb-4 divide-y divide-border">
                  {requirementAnalysis.summary && (
                    <div className="pb-4 mb-1">
                      <div className="text-[11px] font-bold text-txt-muted uppercase tracking-wide mb-1.5">Summary</div>
                      <p className="text-sm leading-relaxed text-txt">{requirementAnalysis.summary}</p>
                    </div>
                  )}
                  {[
                    { key: "functional_requirements" as const, label: "Functional Requirements" },
                    { key: "non_functional_requirements" as const, label: "Non-Functional Requirements" },
                    { key: "acceptance_criteria" as const, label: "Acceptance Criteria" },
                    { key: "edge_cases" as const, label: "Edge Cases" },
                  ].map(({ key, label }) => {
                    const items = requirementAnalysis[key];
                    if (!items?.length) return null;
                    return (
                      <div key={key} className="py-4">
                        <div className="text-[11px] font-bold text-txt-muted uppercase tracking-wide mb-2">{label}</div>
                        <ul className="space-y-1.5">
                          {items.map((f, i) => (
                            <li key={i} className="flex items-start gap-2 text-sm">
                              <span className="w-1 h-1 mt-2 rounded-full bg-txt-muted shrink-0"></span>
                              <span>{f}</span>
                            </li>
                          ))}
                        </ul>
                      </div>
                    );
                  })}
                </div>
              )}

              {!streaming && !requirementAnalysis && (
                <div className="flex items-center justify-center gap-2 py-10 text-sm text-txt-muted">
                  <span className="inline-block w-4 h-4 border-2 rounded-full border-border border-t-magenta animate-spin"></span>
                  Waiting for results…
                </div>
              )}

              {!streaming && (
                <div className="flex gap-2 pt-4 mt-4 border-t border-border">
                  <input
                    className="flex-1 input-field"
                    value={pmFeedback}
                    onChange={(e) => setPmFeedback(e.target.value)}
                    placeholder="Have feedback? Enter here to regenerate…"
                  />
                  <button className="btn-outline" onClick={handlePmRefine} disabled={!pmFeedback.trim() || loading}>Regenerate</button>
                  <button className="btn-magenta" onClick={handleQaRun} disabled={loading || !!pmFeedback.trim()}>Generate QA Cases →</button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 2: QA Test Cases ═══ */}
          {step === 2 && (
            <div className="card">
              <div className="flex items-center justify-between mb-5">
                <div className="flex items-center gap-3">
                  <div className="flex items-center justify-center w-8 h-8 text-base rounded-xl bg-green-50">🧪</div>
                  <h2 className="text-base font-bold">QA Test Cases</h2>
                </div>
                {streaming && (
                  <span className="flex items-center gap-1.5 text-xs font-semibold text-magenta bg-magenta/5 px-3 py-1 rounded-full">
                    <span className="w-1.5 h-1.5 bg-magenta rounded-full animate-pulse inline-block"></span>
                    {qaStreamParsed?.testCases.names.length ?? 0} cases generated
                  </span>
                )}
              </div>

              {/* Streaming preview */}
              {streaming && qaStreamParsed && (
                <div ref={qaStreamRef} className="rounded-xl border border-border bg-[#fafafa] p-4 mb-4 max-h-[55vh] overflow-y-auto space-y-3">
                  <div className="inline-flex items-center gap-1 text-[11px] font-bold px-2 py-0.5 rounded-md mb-1 bg-green-50 text-green-700">🧪 Test Cases</div>
                  <div className="space-y-1.5">
                    {qaStreamParsed.testCases.names.map((name, i) => (
                      <div key={i} className="flex items-center gap-2.5 py-1.5 px-3 bg-white border border-border rounded-lg text-sm">
                        <span className="font-mono text-[11px] font-bold text-magenta bg-magenta/10 px-1.5 py-0.5 rounded shrink-0">
                          TC{String(i + 1).padStart(3, "0")}
                        </span>
                        <span className="text-txt">{name}</span>
                      </div>
                    ))}
                    {qaStreamParsed.testCases.active && (
                      <div className="flex items-center gap-2 text-sm text-txt-muted py-1.5 px-3">
                        <span className="w-3.5 h-3.5 border-2 border-green-200 border-t-green-500 rounded-full animate-spin inline-block"></span>
                        Generating next case…
                      </div>
                    )}
                    {!qaStreamParsed.testCases.names.length && (
                      <div className="flex items-center justify-center gap-2 py-4 text-sm text-txt-muted">
                        <span className="inline-block w-4 h-4 border-2 rounded-full border-magenta/30 border-t-magenta animate-spin"></span>
                        Waiting…
                      </div>
                    )}
                  </div>
                  {qaStreamParsed.testStrategy.value && (
                    <div className="pt-3 border-t border-border">
                      <div className="text-[11px] font-bold text-txt-muted mb-1">📋 Test Strategy</div>
                      <p className="text-sm">{qaStreamParsed.testStrategy.value}{qaStreamParsed.testStrategy.active && <span className="text-magenta animate-pulse">|</span>}</p>
                    </div>
                  )}
                  {qaStreamParsed.coveragePlan.value && (
                    <div className="pt-3 border-t border-border">
                      <div className="text-[11px] font-bold text-txt-muted mb-1">📊 Coverage Plan</div>
                      <p className="text-sm">{qaStreamParsed.coveragePlan.value}{qaStreamParsed.coveragePlan.active && <span className="text-magenta animate-pulse">|</span>}</p>
                    </div>
                  )}
                </div>
              )}

              {/* Final result */}
              {!streaming && testCases.length > 0 && (
                <div className="mb-4 space-y-5">
                  {Object.entries(groupedTestCases).map(([type, cases]) => (
                    <div key={type}>
                      <div className="flex items-center gap-2 mb-2">
                        <span className="text-sm font-bold">{TYPE_EMOJI[type] || "🧪"} {TYPE_LABEL[type] || type}</span>
                        <span className="text-xs text-txt-muted bg-surface-muted px-2 py-0.5 rounded-full">{cases.length}</span>
                      </div>
                      <div className="overflow-x-auto border rounded-xl border-border">
                        <table className="w-full text-sm">
                          <thead>
                            <tr className="text-left bg-[#f9f9f9] border-b border-border">
                              {["ID", "Name", "Precondition", "Steps", "Expected Result"].map(h => (
                                <th key={h} className="px-3 py-2.5 font-semibold text-xs text-txt-muted whitespace-nowrap">{h}</th>
                              ))}
                            </tr>
                          </thead>
                          <tbody>
                            {cases.map((tc, i) => (
                              <tr key={tc.test_id || i} className={`border-b border-border last:border-0 ${ i % 2 === 0 ? "bg-white" : "bg-[#fdfdfd]" }`}>
                                <td className="px-3 py-2.5 font-mono text-[11px] font-bold text-magenta whitespace-nowrap">{tc.test_id}</td>
                                <td className="px-3 py-2.5 font-medium">{tc.test_name}</td>
                                <td className="px-3 py-2.5 text-txt-muted text-xs">{tc.precondition}</td>
                                <td className="px-3 py-2.5">
                                  {Array.isArray(tc.steps) ? (
                                    <ol className="list-decimal list-inside space-y-0.5 text-xs">
                                      {tc.steps.map((s, j) => <li key={j}>{s}</li>)}
                                    </ol>
                                  ) : <span className="text-xs">{tc.steps}</span>}
                                </td>
                                <td className="px-3 py-2.5 text-xs">{tc.expected_result}</td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      </div>
                    </div>
                  ))}
                  {(testStrategy || coveragePlan) && (
                    <div className="grid grid-cols-2 gap-3 pt-1">
                      {testStrategy && (
                        <div className="p-4 bg-white border border-border rounded-xl">
                          <div className="flex items-center gap-1.5 mb-2">
                            <span className="text-sm">📋</span>
                            <span className="text-xs font-bold tracking-wide uppercase text-txt">Test Strategy</span>
                          </div>
                          <p className="text-sm leading-relaxed text-txt-muted">{testStrategy}</p>
                        </div>
                      )}
                      {coveragePlan && (
                        <div className="p-4 bg-white border border-border rounded-xl">
                          <div className="flex items-center gap-1.5 mb-2">
                            <span className="text-sm">📊</span>
                            <span className="text-xs font-bold tracking-wide uppercase text-txt">Coverage Plan</span>
                          </div>
                          <p className="text-sm leading-relaxed text-txt-muted">{coveragePlan}</p>
                        </div>
                      )}
                    </div>
                  )}
                </div>
              )}

              {!streaming && testCases.length === 0 && (
                <div className="flex items-center justify-center gap-2 py-10 text-sm text-txt-muted">
                  <span className="inline-block w-4 h-4 border-2 rounded-full border-border border-t-magenta animate-spin"></span>
                  Waiting for test cases…
                </div>
              )}

              {!streaming && (
                <div className="flex gap-2 pt-4 mt-4 border-t border-border">
                  <input
                    className="flex-1 input-field"
                    value={qaFeedback}
                    onChange={(e) => setQaFeedback(e.target.value)}
                    placeholder="Have feedback? Enter here to regenerate…"
                  />
                  <button className="btn-outline" onClick={handleQaRefine} disabled={!qaFeedback.trim() || loading}>Regenerate</button>
                  <button className="btn-magenta" onClick={handleDevRun} disabled={loading || !!qaFeedback.trim()}>Generate Dev Code →</button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 3: Dev Code Generation ═══ */}
          {step === 3 && (
            <div className="card">
              <div className="flex items-center justify-between mb-5">
                <div className="flex items-center gap-3">
                  <div className="flex items-center justify-center w-8 h-8 text-base bg-gray-100 rounded-xl">💻</div>
                  <h2 className="text-base font-bold">Dev Code Generation</h2>
                </div>
                {streaming && (
                  <span className="flex items-center gap-1.5 text-xs font-semibold text-magenta bg-magenta/5 px-3 py-1 rounded-full">
                    <span className="w-1.5 h-1.5 bg-magenta rounded-full animate-pulse inline-block"></span>
                    Generating… {streamText.length} chars
                  </span>
                )}
              </div>

              {/* Tabs */}
              <div className="flex gap-1 p-1 bg-[#f3f3f3] rounded-xl mb-4">
                {([
                  ["java_code", "🐍 Business Code"],
                  ["unit_tests", "🧪 Unit Tests"],
                  ["implementation_notes", "📄 Implementation Notes"],
                ] as const).map(([key, label]) => (
                  <button
                    key={key}
                    className={`flex-1 px-3 py-1.5 text-sm font-semibold rounded-lg transition-all ${
                      (streaming ? devStreamTab : codeTab) === key
                        ? "bg-white text-magenta shadow-sm"
                        : "text-txt-muted hover:text-txt"
                    }`}
                    onClick={() => streaming ? setDevStreamTab(key) : setCodeTab(key)}
                  >
                    {label}
                  </button>
                ))}
              </div>

              <div className="relative rounded-xl overflow-hidden border border-[#2a2a2a]">
                <div className="flex items-center justify-between px-4 py-2 bg-[#252525] border-b border-[#333]">
                  <div className="flex items-center gap-1.5">
                    <span className="w-2.5 h-2.5 rounded-full bg-[#ff5f57]" />
                    <span className="w-2.5 h-2.5 rounded-full bg-[#febc2e]" />
                    <span className="w-2.5 h-2.5 rounded-full bg-[#28c840]" />
                  </div>
                  <span className="text-[11px] text-gray-500 font-mono">
                    {(streaming ? devStreamTab : codeTab) === "implementation_notes" ? "notes.txt" :
                     (streaming ? devStreamTab : codeTab) === "unit_tests" ? "test_service.py" : "service.py"}
                  </span>
                  {!streaming && (
                    <button
                      className="text-[11px] text-gray-400 hover:text-gray-200 transition-colors"
                      onClick={() => {
                        const code = codeTab === "java_code" ? codeGeneration?.java_code
                          : codeTab === "unit_tests" ? codeGeneration?.unit_tests
                          : codeGeneration?.implementation_notes;
                        if (code) navigator.clipboard.writeText(code);
                      }}
                    >
                      Copy
                    </button>
                  )}
                </div>
                <pre ref={devStreamRef} className="bg-[#1a1a1a] text-gray-300 px-5 py-4 text-[0.82rem] font-mono leading-relaxed max-h-[50vh] overflow-y-auto whitespace-pre-wrap">
                  {streaming
                    ? devStreamParsed?.[devStreamTab] || "Waiting for Dev Agent output…"
                    : codeTab === "java_code"
                      ? codeGeneration?.java_code || "No code yet"
                      : codeTab === "unit_tests"
                        ? codeGeneration?.unit_tests || "No tests yet"
                        : parseNotes(codeGeneration?.implementation_notes || "").join("\n") || "No notes yet"
                  }
                </pre>
              </div>

              {!streaming && (
                <div className="flex justify-end pt-4 mt-4 border-t border-border">
                  <button className="btn-magenta" onClick={handleTestRun} disabled={loading}>
                    ▶ Run Unit Tests
                  </button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 4: Test Execution ═══ */}
          {step === 4 && (
            <div className="card">
              <div className="flex items-center justify-between mb-5">
                <div className="flex items-center gap-3">
                  <div className="flex items-center justify-center w-8 h-8 text-base rounded-xl bg-purple-50">▶</div>
                  <h2 className="text-base font-bold">Test Execution</h2>
                </div>
                {loading && (
                  <span className="flex items-center gap-1.5 text-xs font-semibold text-magenta bg-magenta/5 px-3 py-1 rounded-full">
                    <span className="w-3.5 h-3.5 border-2 border-magenta/30 border-t-magenta rounded-full animate-spin inline-block"></span>
                    Running…
                  </span>
                )}
              </div>

              {testExecution ? (
                <>
                  {/* 状态横幅 */}
                  <div className={`flex items-center gap-3 px-5 py-4 rounded-xl mb-5 ${
                    testExecution.success
                      ? "bg-green-50 border border-green-200"
                      : "bg-red-50 border border-red-200"
                  }`}>
                    <span className="text-2xl">{testExecution.success ? "✅" : "❌"}</span>
                    <div>
                      <div className={`text-sm font-bold ${ testExecution.success ? "text-green-800" : "text-red-800" }`}>
                        {testExecution.success
                          ? `All ${testExecution.total} tests passed!`
                          : `${testExecution.failed + testExecution.errors} test(s) failed`
                        }
                      </div>
                      {!testExecution.success && (
                        <div className="text-xs text-red-600 mt-0.5">Click "AI Auto Fix" to automatically fix the failing tests.</div>
                      )}
                    </div>
                  </div>

                  {/* 数据统计 */}
                  <div className="grid grid-cols-4 gap-3 mb-5">
                    {[
                      { num: testExecution.passed, label: "Passed", color: "text-green-600", bg: "bg-green-50 border-green-100", icon: "✅" },
                      { num: testExecution.failed, label: "Failed", color: "text-red-500", bg: "bg-red-50 border-red-100", icon: "❌" },
                      { num: testExecution.errors, label: "Errors", color: "text-amber-500", bg: "bg-amber-50 border-amber-100", icon: "⚠️" },
                      { num: testExecution.total, label: "Total", color: "text-txt", bg: "bg-[#f9f9f9] border-border", icon: "📊" },
                    ].map(({ num, label, color, bg, icon }) => (
                      <div key={label} className={`border rounded-xl p-4 text-center ${bg}`}>
                        <div className={`text-3xl font-extrabold mb-1 ${color}`}>{num}</div>
                        <div className="text-[11px] font-semibold text-txt-muted">{icon} {label}</div>
                      </div>
                    ))}
                  </div>

                  {/* 输出 */}
                  <div className="relative rounded-xl overflow-hidden border border-[#2a2a2a]">
                    <div className="flex items-center justify-between px-4 py-2 bg-[#252525] border-b border-[#333]">
                      <span className="text-[11px] text-gray-400 font-semibold">🖥 pytest output</span>
                      <button
                        className="text-[11px] text-gray-400 hover:text-gray-200 transition-colors"
                        onClick={() => navigator.clipboard.writeText(testExecution.output)}
                      >
                        Copy
                      </button>
                    </div>
                    <pre className="bg-[#1a1a1a] text-gray-300 px-5 py-4 text-[0.82rem] font-mono leading-relaxed max-h-[40vh] overflow-y-auto whitespace-pre-wrap">
                      {testExecution.output}
                    </pre>
                  </div>

                  <div className="flex justify-end gap-2 pt-4 mt-4 border-t border-border">
                    <button className="btn-outline" onClick={handleTestRun} disabled={loading}>🔄 Re-run</button>
                    {!testExecution.success && (
                      <button className="btn-magenta" onClick={handleTestFix} disabled={loading || streaming}>
                        🔧 AI Auto Fix
                      </button>
                    )}
                  </div>
                </>
              ) : (
                <div className="flex flex-col items-center justify-center gap-3 py-14">
                  {loading ? (
                    <>
                      <span className="w-8 h-8 border-2 rounded-full border-magenta/20 border-t-magenta animate-spin"></span>
                      <span className="text-sm text-txt-muted">Running pytest…</span>
                    </>
                  ) : (
                    <>
                      <span className="text-3xl">🧪</span>
                      <span className="text-sm text-txt-muted">Ready. Click the button below to run tests.</span>
                      <button className="mt-2 btn-magenta" onClick={handleTestRun}>▶ Run Unit Tests</button>
                    </>
                  )}
                </div>
              )}
            </div>
          )}

          <div ref={bottomRef} />
        </div>
      </div>
    </div>
  );
}
