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

/* ─── Types ─── */
type Step = 0 | 1 | 2 | 3 | 4;

type ClarifyMsg = { role: "user" | "assistant"; content: string };

type PMResult = {
  summary: string;
  functional: string[];
  nonfunctional: string[];
  acceptance: string[];
  edge_cases: string[];
};

type TestCase = {
  id: string;
  name: string;
  precondition: string;
  steps: string;
  expected: string;
};

type TestResult = {
  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();
}

async function readSSE(path: string, onChunk: (text: string) => 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 });
      // process SSE lines
      let idx = buf.indexOf("\n");
      while (idx >= 0) {
        const line = buf.slice(0, idx).trim();
        buf = buf.slice(idx + 1);
        if (line.startsWith("data:")) {
          const payload = line.slice(5).trim();
          if (payload === "[DONE]") return;
          try {
            const evt = JSON.parse(payload);
            if (evt.text) onChunk(evt.text);
            else if (evt.message) onChunk(evt.message);
            else if (typeof evt === "string") onChunk(evt);
          } catch {
            onChunk(payload);
          }
        }
        idx = buf.indexOf("\n");
      }
    }
  } finally {
    reader.releaseLock();
  }
}

/* ── Step labels ── */
const STEPS: { title: string; icon: string }[] = [
  { title: "Clarification", icon: "💬" },
  { title: "PM Analysis", icon: "📋" },
  { title: "QA Cases", icon: "🧪" },
  { title: "Dev Output", icon: "💻" },
  { title: "Test Run", icon: "▶" },
];

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

  // Step 0 — Requirement
  const [requirement, setRequirement] = useState("");
  const [rawReq, setRawReq] = useState("");
  const [status, setStatus] = useState<string>("");
  const [clarifyHistory, setClarifyHistory] = useState<ClarifyMsg[]>([]);
  const [clarifyInput, setClarifyInput] = useState("");

  // Step 1 — PM analysis
  const [pmStream, setPmStream] = useState("");
  const [pmResult, setPmResult] = useState<PMResult | null>(null);
  const [pmFeedback, setPmFeedback] = useState("");

  // Step 2 — QA test cases
  const [qaStream, setQaStream] = useState("");
  const [testCases, setTestCases] = useState<TestCase[]>([]);
  const [qaFeedback, setQaFeedback] = useState("");

  // Step 3 — Dev code
  const [devStream, setDevStream] = useState("");
  const [codeTab, setCodeTab] = useState<"code" | "test" | "notes">("code");
  const [devCode, setDevCode] = useState("");
  const [devTest, setDevTest] = useState("");
  const [devNotes, setDevNotes] = useState("");

  // Step 4 — Test results
  const [testResult, setTestResult] = useState<TestResult | null>(null);

  const abortRef = useRef<AbortController | null>(null);
  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [pmStream, qaStream, devStream]);

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

  /* ── Step 0: Start session ── */
  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);
      setRawReq(requirement.trim());
      setStatus(data.status || "clarifying");
      if (data.clarify_questions) {
        setClarifyHistory([{ role: "assistant", content: data.clarify_questions }]);
      }
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [requirement, loading]);

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

  /* ── Step 1: PM Run ── */
  const handlePmRun = useCallback(async () => {
    setStep(1);
    setLoading(true);
    setError("");
    setPmStream("");
    try {
      await apiPost(`/session/${sessionId}/pm/run`);
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      let full = "";
      await readSSE(`/session/${sessionId}/pm/stream`, (text) => {
        full += text;
        setPmStream(full);
      }, ctrl.signal);
      // Try to parse structured result
      try {
        const json = JSON.parse(full);
        setPmResult(json);
      } catch {
        setPmResult({ summary: full, functional: [], nonfunctional: [], acceptance: [], edge_cases: [] });
      }
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId]);

  /* ── Step 1: PM Refine ── */
  const handlePmRefine = useCallback(async () => {
    if (!pmFeedback.trim()) return;
    setLoading(true);
    setPmStream("");
    try {
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      let full = "";
      await readSSE(
        `/session/${sessionId}/pm/refine/stream?feedback=${encodeURIComponent(pmFeedback.trim())}`,
        (text) => {
          full += text;
          setPmStream(full);
        },
        ctrl.signal,
      );
      setPmFeedback("");
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId, pmFeedback]);

  /* ── Step 2: QA Run ── */
  const handleQaRun = useCallback(async () => {
    setStep(2);
    setLoading(true);
    setError("");
    setQaStream("");
    try {
      await apiPost(`/session/${sessionId}/qa/run`);
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      let full = "";
      await readSSE(`/session/${sessionId}/qa/stream`, (text) => {
        full += text;
        setQaStream(full);
      }, ctrl.signal);
      // Try parse
      try {
        const json = JSON.parse(full);
        if (json.test_cases) setTestCases(json.test_cases);
      } catch {
        /* raw display */
      }
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId]);

  /* ── Step 3: Dev Run ── */
  const handleDevRun = useCallback(async () => {
    setStep(3);
    setLoading(true);
    setError("");
    setDevStream("");
    try {
      await apiPost(`/session/${sessionId}/dev/run`);
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      let full = "";
      await readSSE(`/session/${sessionId}/dev/stream`, (text) => {
        full += text;
        setDevStream(full);
      }, ctrl.signal);
      // Parse code blocks
      try {
        const json = JSON.parse(full);
        setDevCode(json.code || json.implementation || full);
        setDevTest(json.tests || json.test_code || "");
        setDevNotes(json.notes || json.implementation_notes || "");
      } catch {
        setDevCode(full);
      }
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId]);

  /* ── Step 4: Test Run ── */
  const handleTestRun = useCallback(async () => {
    setStep(4);
    setLoading(true);
    setError("");
    try {
      const data: any = await apiPost(`/session/${sessionId}/test/run`);
      setTestResult({
        passed: data.passed ?? 0,
        failed: data.failed ?? 0,
        errors: data.errors ?? 0,
        total: data.total ?? 0,
        output: data.output || data.detail || JSON.stringify(data, null, 2),
      });
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId]);

  /* ── Test Fix ── */
  const handleTestFix = useCallback(async () => {
    setLoading(true);
    try {
      const ctrl = new AbortController();
      abortRef.current = ctrl;
      let full = "";
      await readSSE(`/session/${sessionId}/test/fix/stream`, (text) => {
        full += text;
        setDevStream(full);
      }, ctrl.signal);
      // Re-run test
      await handleTestRun();
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }, [sessionId, handleTestRun]);

  return (
    <div className="flex flex-col h-full overflow-hidden">
      {/* ── Step bar ── */}
      <div className="flex items-center gap-1 px-10 py-4 border-b border-border bg-white/80 backdrop-blur shrink-0">
        {STEPS.map((s, i) => (
          <div key={i} className="flex items-center gap-1">
            <button
              onClick={() => { if (sessionId && i <= step) setStep(i as Step); }}
              className={`flex items-center gap-2 px-4 py-2 text-sm font-bold transition-colors ${
                i === step
                  ? "text-magenta"
                  : i < step
                    ? "text-green-600"
                    : "text-txt-muted"
              } ${i <= step ? "cursor-pointer hover:text-magenta" : "cursor-default"}`}
            >
              <span>{i < step ? "✓" : s.icon}</span>
              <span>{s.title}</span>
            </button>
            {i < STEPS.length - 1 && <span className="text-gray-300 mx-1">→</span>}
          </div>
        ))}
      </div>

      {/* Error banner */}
      {error && (
        <div className="mx-10 mt-4 px-4 py-2 bg-red-50 text-red-700 text-sm flex justify-between items-center">
          {error}
          <button className="font-bold text-red-400 hover:text-red-600" onClick={() => setError("")}>✕</button>
        </div>
      )}

      {/* ── Content ── */}
      <div className="flex-1 overflow-y-auto px-10 py-8">
        <div className="max-w-4xl mx-auto">

          {/* ═══ Step 0: Requirement ═══ */}
          {step === 0 && !sessionId && (
            <div className="card">
              <h2 className="text-lg font-extrabold mb-1">📋 Describe Product Requirement</h2>
              <p className="text-sm text-txt-muted mb-6">Enter your product requirement, the system will automatically perform requirement clarification and analysis</p>
              <textarea
                className="input-field min-h-[160px] resize-y mb-4"
                value={requirement}
                onChange={(e) => setRequirement(e.target.value)}
                placeholder="Example: Build a predictive battery maintenance system for 500k concurrent uploads with end-to-end latency < 3s..."
              />
              <div className="flex justify-end">
                <button className="btn-magenta" onClick={handleStart} disabled={loading || !requirement.trim()}>
                  {loading ? "Creating..." : "Start Analysis →"}
                </button>
              </div>
            </div>
          )}

          {step === 0 && sessionId && (
            <div className="card">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-lg">💬</span>
                <h2 className="text-lg font-extrabold">Requirement Clarification</h2>
                <span className={`badge ${status === "clarifying" ? "bg-yellow-100 text-yellow-700" : "bg-green-100 text-green-700"}`}>
                  {status === "clarifying" ? "Clarifying" : "Confirmed"}
                </span>
              </div>

              {/* Original req */}
              <div className="bg-surface-muted p-4 mb-4 text-sm">
                <span className="text-xs font-bold text-txt-muted block mb-1">📋 Original Requirement</span>
                {rawReq}
              </div>

              {/* Chat history */}
              {clarifyHistory.length > 0 && (
                <div className="flex flex-col gap-3 mb-4">
                  {clarifyHistory.map((msg, i) => (
                    <div
                      key={i}
                      className={`max-w-[80%] px-4 py-3 text-sm ${
                        msg.role === "user"
                          ? "self-end bg-surface-muted"
                          : "self-start border border-border border-l-4 border-l-magenta"
                      }`}
                    >
                      <span className="text-xs font-bold text-txt-muted block mb-1">
                        {msg.role === "assistant" ? "🤖 AI" : "👤 You"}
                      </span>
                      {msg.content}
                    </div>
                  ))}
                </div>
              )}

              {/* Clarify input */}
              {status === "clarifying" && (
                <div className="border-t border-border pt-4 mt-4">
                  <p className="text-sm font-bold text-txt-muted mb-2">💬 Answer the AI follow-up:</p>
                  <textarea
                    className="input-field min-h-[80px] resize-y mb-3"
                    value={clarifyInput}
                    onChange={(e) => setClarifyInput(e.target.value)}
                    placeholder="Add extra context..."
                    disabled={loading}
                  />
                  <div className="flex justify-end">
                    <button className="btn-magenta" onClick={handleClarify} disabled={loading}>
                      {loading ? "Sending..." : "Send"}
                    </button>
                  </div>
                </div>
              )}

              {/* Ready for PM */}
              {status !== "clarifying" && (
                <div className="border-t border-border pt-4 mt-4">
                  <div className="bg-green-50 text-green-800 px-4 py-2 text-sm mb-4">
                    ✅ Requirement is confirmed and ready for PM analysis.
                  </div>
                  <div className="flex justify-end">
                    <button className="btn-magenta" onClick={handlePmRun} disabled={loading}>
                      {loading ? "Analyzing..." : "Run PM Analysis →"}
                    </button>
                  </div>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 1: PM Analysis ═══ */}
          {step === 1 && (
            <div className="card">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-lg">📋</span>
                <h2 className="text-lg font-extrabold">PM Requirement Analysis</h2>
                {loading && <span className="text-xs text-magenta font-bold animate-pulse">Streaming output...</span>}
              </div>

              {/* Streaming/result display */}
              <div className="bg-surface-muted p-6 text-sm leading-relaxed whitespace-pre-wrap mb-4 max-h-[50vh] overflow-y-auto">
                {pmStream || "Waiting for stream..."}
              </div>

              {/* Structured result sections */}
              {pmResult && pmResult.functional?.length > 0 && (
                <div className="space-y-3 mb-4">
                  {pmResult.summary && (
                    <div><span className="text-xs font-bold text-txt-muted">📌 Summary</span><p className="text-sm mt-1">{pmResult.summary}</p></div>
                  )}
                  {pmResult.functional.length > 0 && (
                    <div>
                      <span className="text-xs font-bold text-txt-muted">🔧 Functional Requirements</span>
                      <ul className="text-sm mt-1 list-disc list-inside">{pmResult.functional.map((f, i) => <li key={i}>{f}</li>)}</ul>
                    </div>
                  )}
                </div>
              )}

              {/* Feedback */}
              {!loading && (
                <div className="border-t border-border pt-4 mt-4 flex gap-3">
                  <input
                    className="input-field flex-1"
                    value={pmFeedback}
                    onChange={(e) => setPmFeedback(e.target.value)}
                    placeholder="Provide feedback to refine PM output..."
                  />
                  <button className="btn-outline" onClick={handlePmRefine} disabled={!pmFeedback.trim()}>Refine</button>
                  <button className="btn-magenta" onClick={handleQaRun}>Generate QA Cases →</button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 2: QA Test Cases ═══ */}
          {step === 2 && (
            <div className="card">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-lg">🧪</span>
                <h2 className="text-lg font-extrabold">QA Test Cases</h2>
                {loading && <span className="text-xs text-magenta font-bold animate-pulse">Generating...</span>}
              </div>

              {/* Test cases table */}
              {testCases.length > 0 ? (
                <div className="overflow-x-auto mb-4">
                  <table className="w-full text-sm border border-border">
                    <thead>
                      <tr className="bg-surface-muted text-left">
                        <th className="px-3 py-2 border-b border-border font-bold">ID</th>
                        <th className="px-3 py-2 border-b border-border font-bold">Case</th>
                        <th className="px-3 py-2 border-b border-border font-bold">Precondition</th>
                        <th className="px-3 py-2 border-b border-border font-bold">Steps</th>
                        <th className="px-3 py-2 border-b border-border font-bold">Expected</th>
                      </tr>
                    </thead>
                    <tbody>
                      {testCases.map((tc, i) => (
                        <tr key={tc.id || i} className="border-b border-border">
                          <td className="px-3 py-2 font-mono text-xs">{tc.id}</td>
                          <td className="px-3 py-2">{tc.name}</td>
                          <td className="px-3 py-2 text-txt-muted">{tc.precondition}</td>
                          <td className="px-3 py-2">{tc.steps}</td>
                          <td className="px-3 py-2">{tc.expected}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              ) : (
                <div className="bg-surface-muted p-6 text-sm leading-relaxed whitespace-pre-wrap mb-4 max-h-[50vh] overflow-y-auto">
                  {qaStream || "Waiting for stream..."}
                </div>
              )}

              {!loading && (
                <div className="border-t border-border pt-4 mt-4 flex gap-3">
                  <input
                    className="input-field flex-1"
                    value={qaFeedback}
                    onChange={(e) => setQaFeedback(e.target.value)}
                    placeholder="Provide feedback to refine QA output..."
                  />
                  <button className="btn-outline" disabled={!qaFeedback.trim()}>Refine</button>
                  <button className="btn-magenta" onClick={handleDevRun}>Generate Dev Output →</button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 3: Dev Code ═══ */}
          {step === 3 && (
            <div className="card">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-lg">💻</span>
                <h2 className="text-lg font-extrabold">Dev Code Generation</h2>
                {loading && <span className="text-xs text-magenta font-bold animate-pulse">Generating...</span>}
              </div>

              {/* Tabs */}
              <div className="flex gap-1 mb-4 border-b border-border">
                {(
                  [
                    ["code", "🐍 Service Code"],
                    ["test", "🧪 Unit Tests"],
                    ["notes", "📄 Notes"],
                  ] as const
                ).map(([key, label]) => (
                  <button
                    key={key}
                    className={`px-4 py-2 text-sm font-bold border-b-2 transition-colors ${
                      codeTab === key ? "border-magenta text-magenta" : "border-transparent text-txt-muted hover:text-txt"
                    }`}
                    onClick={() => setCodeTab(key)}
                  >
                    {label}
                  </button>
                ))}
              </div>

              <div className="bg-surface-dark text-gray-300 p-6 text-[0.85rem] font-mono leading-relaxed max-h-[50vh] overflow-y-auto whitespace-pre-wrap">
                {loading
                  ? devStream || "Waiting for stream..."
                  : codeTab === "code"
                    ? devCode || "No service code"
                    : codeTab === "test"
                      ? devTest || "No test code"
                      : devNotes || "No notes"
                }
              </div>

              {!loading && (
                <div className="border-t border-border pt-4 mt-4 flex justify-end gap-3">
                  <button
                    className="btn-outline"
                    onClick={() => {
                      navigator.clipboard.writeText(codeTab === "code" ? devCode : codeTab === "test" ? devTest : devNotes);
                    }}
                  >
                    Copy
                  </button>
                  <button className="btn-magenta" onClick={handleTestRun}>Run Tests →</button>
                </div>
              )}
            </div>
          )}

          {/* ═══ Step 4: Test Execution ═══ */}
          {step === 4 && (
            <div className="card">
              <div className="flex items-center gap-3 mb-4">
                <span className="text-lg">▶</span>
                <h2 className="text-lg font-extrabold">Test Execution</h2>
                {loading && <span className="text-xs text-magenta font-bold animate-pulse">Running...</span>}
              </div>

              {testResult ? (
                <>
                  {/* Stats */}
                  <div className="grid grid-cols-4 gap-4 mb-6">
                    <div className="bg-green-50 p-4 text-center">
                      <div className="text-2xl font-extrabold text-green-600">{testResult.passed}</div>
                      <div className="text-xs font-bold text-green-700 mt-1">✅ Passed</div>
                    </div>
                    <div className="bg-red-50 p-4 text-center">
                      <div className="text-2xl font-extrabold text-red-600">{testResult.failed}</div>
                      <div className="text-xs font-bold text-red-700 mt-1">❌ Failed</div>
                    </div>
                    <div className="bg-yellow-50 p-4 text-center">
                      <div className="text-2xl font-extrabold text-yellow-600">{testResult.errors}</div>
                      <div className="text-xs font-bold text-yellow-700 mt-1">⚠️ Errors</div>
                    </div>
                    <div className="bg-surface-muted p-4 text-center">
                      <div className="text-2xl font-extrabold text-txt">{testResult.total}</div>
                      <div className="text-xs font-bold text-txt-muted mt-1">Total</div>
                    </div>
                  </div>

                  {/* Output */}
                  <pre className="bg-surface-dark text-gray-300 p-6 text-[0.85rem] font-mono leading-relaxed max-h-[40vh] overflow-y-auto whitespace-pre-wrap">
                    {testResult.output}
                  </pre>

                  <div className="border-t border-border pt-4 mt-4 flex justify-end gap-3">
                    <button className="btn-outline" onClick={handleTestRun} disabled={loading}>
                      Re-run
                    </button>
                    {testResult.failed > 0 && (
                      <button className="btn-magenta" onClick={handleTestFix} disabled={loading}>
                        AI Auto-fix
                      </button>
                    )}
                  </div>
                </>
              ) : (
                <div className="text-center py-12 text-txt-muted text-sm">
                  {loading ? "Running pytest..." : "Waiting for test execution"}
                </div>
              )}
            </div>
          )}

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