"use client";

import { useState, useCallback, useMemo } from "react";
import { CodeEditor } from "./code-editor";
import { TestResults } from "./test-results";
import { usePyodide } from "@/hooks/use-pyodide";
import { submitSolution } from "@/lib/api";
import type { QuestionDetail, TestResult, HiddenTestOutput } from "@/types";
import { Badge } from "@/components/ui/badge";
import { Markdown } from "@/components/ui/markdown";
import { CodeBlock } from "@/components/ui/code-block";
import { Callout, ApproachBox } from "@/components/ui/callout";
import { Collapsible } from "@/components/ui/collapsible";
import { getDifficultyVariant, capitalize } from "@/lib/utils";
import {
  FileText,
  BookOpen,
  AlertCircle,
  Brain,
  ClipboardList,
  AlertTriangle,
  Lightbulb,
  Code,
  Play,
  Send,
  Loader2,
} from "lucide-react";
import Link from "next/link";

interface ProblemWorkspaceProps {
  question: QuestionDetail;
}

interface ExecutionResult {
  test_id: number;
  output: unknown;
  error?: string;
}

function extractFunctionName(signature: string): string {
  const match = signature.match(/def\s+(\w+)\s*\(/);
  return match ? match[1] : "solution";
}

function generateStarterCode(signature: string): string {
  return `${signature}
    # Write your solution here
    pass
`;
}

type LeftTab = "problem" | "explanation";
type RightTab = "code" | "results";

export function ProblemWorkspace({ question }: ProblemWorkspaceProps) {
  const starterCode = useMemo(
    () => generateStarterCode(question.function_signature!),
    [question.function_signature]
  );
  const [code, setCode] = useState(starterCode);
  const [leftTab, setLeftTab] = useState<LeftTab>("problem");
  const [rightTab, setRightTab] = useState<RightTab>("code");
  const [hasRunTests, setHasRunTests] = useState(false);

  // Test execution state
  const { pyodide, loading: pyodideLoading, runPython } = usePyodide();
  const [isRunning, setIsRunning] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [visibleResults, setVisibleResults] = useState<TestResult[]>([]);
  const [hiddenPassedCount, setHiddenPassedCount] = useState(0);
  const [hiddenTotalCount, setHiddenTotalCount] = useState(0);

  const functionName = useMemo(
    () => extractFunctionName(question.function_signature!),
    [question.function_signature]
  );

  const visibleTestCases = useMemo(
    () => question.visible_test_cases ?? [],
    [question.visible_test_cases]
  );
  const hiddenTestInputs = useMemo(
    () => question.hidden_test_inputs ?? [],
    [question.hidden_test_inputs]
  );

  const handleReset = useCallback(() => {
    setCode(starterCode);
  }, [starterCode]);

  const generateTestHarness = useCallback(
    (tests: Array<{ id: number; input: Record<string, unknown> }>) => {
      const testsJson = JSON.stringify(tests);
      return `
import json

${code}

__tests__ = json.loads('${testsJson.replace(/'/g, "\\'")}')
__results__ = []

for test in __tests__:
    try:
        result = ${functionName}(**test["input"])
        __results__.append({"test_id": test["id"], "output": result})
    except Exception as e:
        __results__.append({"test_id": test["id"], "output": None, "error": str(e)})

json.dumps(__results__)
`;
    },
    [code, functionName]
  );

  const runTests = useCallback(
    async (tests: Array<{ id: number; input: Record<string, unknown> }>) => {
      const harness = generateTestHarness(tests);
      const { output, error } = await runPython(harness);

      if (error) {
        return tests.map((t) => ({
          test_id: t.id,
          output: null,
          error: error,
        }));
      }

      try {
        return JSON.parse(output as string) as ExecutionResult[];
      } catch {
        return tests.map((t) => ({
          test_id: t.id,
          output: null,
          error: "Failed to parse output",
        }));
      }
    },
    [generateTestHarness, runPython]
  );

  const handleRunTests = useCallback(async () => {
    if (!pyodide || isRunning) return;

    setIsRunning(true);
    setHiddenPassedCount(0);
    setHiddenTotalCount(0);

    try {
      const tests = visibleTestCases.map((tc) => ({
        id: tc.id,
        input: tc.input,
      }));
      const results = await runTests(tests);

      const testResults: TestResult[] = results.map((r, idx) => {
        const testCase = visibleTestCases[idx];
        const passed =
          !r.error &&
          JSON.stringify(r.output) === JSON.stringify(testCase.expected);

        return {
          test_id: r.test_id,
          passed,
          input: testCase.input,
          expected: testCase.expected,
          actual: r.output,
          error: r.error,
        };
      });

      setVisibleResults(testResults);
      setHasRunTests(true);
      setRightTab("results");
    } finally {
      setIsRunning(false);
    }
  }, [pyodide, isRunning, visibleTestCases, runTests]);

  const handleSubmit = useCallback(async () => {
    if (!pyodide || isSubmitting) return;

    setIsSubmitting(true);

    try {
      // Run visible tests first
      const visibleTests = visibleTestCases.map((tc) => ({
        id: tc.id,
        input: tc.input,
      }));
      const visibleExecutionResults = await runTests(visibleTests);

      const visibleTestResults: TestResult[] = visibleExecutionResults.map(
        (r, idx) => {
          const testCase = visibleTestCases[idx];
          const passed =
            !r.error &&
            JSON.stringify(r.output) === JSON.stringify(testCase.expected);

          return {
            test_id: r.test_id,
            passed,
            input: testCase.input,
            expected: testCase.expected,
            actual: r.output,
            error: r.error,
          };
        }
      );

      setVisibleResults(visibleTestResults);

      // Run hidden tests
      const hiddenTests = hiddenTestInputs.map((tc) => ({
        id: tc.id,
        input: tc.input,
      }));
      const hiddenExecutionResults = await runTests(hiddenTests);

      // Submit hidden outputs to server for validation
      const hiddenOutputs: HiddenTestOutput[] = hiddenExecutionResults.map(
        (r) => ({
          test_id: r.test_id,
          output: r.output,
        })
      );

      const response = await submitSolution(question.slug, {
        code,
        hidden_outputs: hiddenOutputs,
      });

      setHiddenPassedCount(response.total_passed);
      setHiddenTotalCount(response.total_tests);
      setHasRunTests(true);
      setRightTab("results");
    } catch (error) {
      console.error("Submission error:", error);
    } finally {
      setIsSubmitting(false);
    }
  }, [
    pyodide,
    isSubmitting,
    visibleTestCases,
    hiddenTestInputs,
    runTests,
    question.slug,
    code,
  ]);

  const isLoading = isRunning || isSubmitting;

  return (
    <div className="fixed inset-0 top-[65px] flex bg-[var(--background)]">
      {/* Left panel - Problem description / Explanation */}
      <div className="w-1/2 border-r border-[var(--border)] flex flex-col">
        {/* Header - compact */}
        <div className="px-4 pt-3 pb-0">
          <div className="flex items-center justify-between gap-2 mb-2">
            <div className="flex items-center gap-3">
              <Link
                href="/questions"
                className="text-xs text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
              >
                &larr; Back
              </Link>
              <h1 className="text-lg font-bold">{question.title}</h1>
              <Badge variant={getDifficultyVariant(question.difficulty)} className="text-xs">
                {capitalize(question.difficulty)}
              </Badge>
            </div>
            {question.leetcode_url && (
              <a
                href={question.leetcode_url}
                target="_blank"
                rel="noopener noreferrer"
                className="text-[var(--primary)] hover:underline text-xs"
              >
                LeetCode ↗
              </a>
            )}
          </div>

          <div className="flex flex-wrap gap-1.5 mb-2">
            {question.categories.map((cat) => (
              <Link key={cat.id} href={`/questions?category=${cat.slug}`}>
                <Badge variant="category" className="text-xs py-0">
                  {cat.name}
                </Badge>
              </Link>
            ))}
            {question.patterns.map((pat) => (
              <Link key={pat.id} href={`/patterns/${pat.slug}`}>
                <Badge variant="pattern" className="text-xs py-0">
                  {pat.name}
                </Badge>
              </Link>
            ))}
          </div>

          {/* Tabs */}
          <div className="flex gap-1 border-b border-[var(--border)]">
            <button
              onClick={() => setLeftTab("problem")}
              className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
                leftTab === "problem"
                  ? "border-[var(--primary)] text-[var(--foreground)]"
                  : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
              }`}
            >
              Problem
            </button>
            <button
              onClick={() => setLeftTab("explanation")}
              className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
                leftTab === "explanation"
                  ? "border-[var(--primary)] text-[var(--foreground)]"
                  : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
              }`}
            >
              Explanation
            </button>
          </div>
        </div>

        {/* Tab content - scrollable */}
        <div className="flex-1 overflow-auto px-4 py-3">
          {leftTab === "problem" ? (
            <div className="space-y-6">
              {/* Problem */}
              <div>
                <h2 className="flex items-center gap-2 text-lg font-semibold mb-3">
                  <FileText className="h-5 w-5" />
                  Problem
                </h2>
                <div className="prose-content">
                  <Markdown>{question.description}</Markdown>
                </div>
              </div>

              {/* Constraints */}
              {question.constraints && (
                <div>
                  <h2 className="flex items-center gap-2 text-lg font-semibold mb-3">
                    <AlertCircle className="h-5 w-5" />
                    Constraints
                  </h2>
                  <Markdown>{question.constraints}</Markdown>
                </div>
              )}

              {/* Examples */}
              {question.examples && question.examples.length > 0 && (
                <div>
                  <h2 className="flex items-center gap-2 text-lg font-semibold mb-3">
                    <BookOpen className="h-5 w-5" />
                    Examples
                  </h2>
                  <div className="space-y-3">
                    {question.examples.map((example, i) => (
                      <div
                        key={i}
                        className="p-3 rounded bg-[var(--secondary)] space-y-1"
                      >
                        <div>
                          <span className="font-medium">Input: </span>
                          <code>{example.input}</code>
                        </div>
                        <div>
                          <span className="font-medium">Output: </span>
                          <code>{example.output}</code>
                        </div>
                        {example.explanation && (
                          <div className="text-sm text-[var(--muted-foreground)]">
                            {example.explanation}
                          </div>
                        )}
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </div>
          ) : (
            <div className="space-y-6">
              {/* Intuition */}
              {question.explanation?.intuition && (
                <Callout variant="insight" icon={Brain} title="Intuition">
                  <Markdown>{question.explanation.intuition}</Markdown>
                </Callout>
              )}

              {/* Approach */}
              {question.explanation?.approach && (
                <Callout variant="info" icon={ClipboardList} title="Approach">
                  <Markdown>{question.explanation.approach}</Markdown>
                </Callout>
              )}

              {/* Common Pitfalls */}
              {question.explanation?.common_pitfalls &&
                question.explanation.common_pitfalls.length > 0 && (
                  <Callout
                    variant="warning"
                    icon={AlertTriangle}
                    title="Common Pitfalls"
                  >
                    <div className="space-y-4">
                      {question.explanation.common_pitfalls.map((pitfall, i) => (
                        <div key={i}>
                          <h4 className="font-medium mb-2">{pitfall.title}</h4>
                          <Markdown>{pitfall.description}</Markdown>
                          {pitfall.wrong_approach && pitfall.correct_approach && (
                            <div className="mt-2 flex gap-2 flex-wrap">
                              <ApproachBox variant="wrong">
                                {pitfall.wrong_approach}
                              </ApproachBox>
                              <ApproachBox variant="correct">
                                {pitfall.correct_approach}
                              </ApproachBox>
                            </div>
                          )}
                        </div>
                      ))}
                    </div>
                  </Callout>
                )}

              {/* Key Takeaways */}
              {question.explanation?.key_takeaways &&
                question.explanation.key_takeaways.length > 0 && (
                  <Callout
                    variant="success"
                    icon={Lightbulb}
                    title="Key Takeaways"
                  >
                    <ul className="space-y-2">
                      {question.explanation.key_takeaways.map((takeaway, i) => (
                        <li
                          key={i}
                          className="[&>div]:inline [&>div>p]:inline"
                        >
                          <Markdown>{takeaway}</Markdown>
                        </li>
                      ))}
                    </ul>
                  </Callout>
                )}

              {/* Complexity Analysis */}
              {(question.explanation?.time_complexity ||
                question.explanation?.space_complexity) && (
                <div>
                  <h2 className="flex items-center gap-2 text-lg font-semibold mb-3">
                    Complexity Analysis
                  </h2>
                  <div className="space-y-2">
                    {question.explanation?.time_complexity && (
                      <p>
                        <strong>Time:</strong>{" "}
                        <Markdown>
                          {question.explanation.time_complexity}
                        </Markdown>
                      </p>
                    )}
                    {question.explanation?.space_complexity && (
                      <p>
                        <strong>Space:</strong>{" "}
                        <Markdown>
                          {question.explanation.space_complexity}
                        </Markdown>
                      </p>
                    )}
                  </div>
                </div>
              )}

              {/* Solutions */}
              {question.solutions && question.solutions.length > 0 && (
                <div>
                  <h2 className="flex items-center gap-2 text-lg font-semibold mb-3">
                    <Code className="h-5 w-5" />
                    Solutions
                  </h2>
                  <div className="space-y-4">
                    {question.solutions.map((solution, i) => {
                      const content = (
                        <div className="space-y-3">
                          <div className="flex items-center gap-2">
                            <h3 className="font-medium">
                              {solution.approach_name}
                            </h3>
                            {solution.is_optimal && (
                              <Badge variant="optimal">Optimal</Badge>
                            )}
                          </div>
                          <CodeBlock language="python" code={solution.code} />
                          {solution.explanation && (
                            <div className="text-sm text-[var(--muted-foreground)]">
                              <Markdown>{solution.explanation}</Markdown>
                            </div>
                          )}
                        </div>
                      );

                      return solution.is_optimal ? (
                        <div key={i}>{content}</div>
                      ) : (
                        <Collapsible
                          key={i}
                          title={`${solution.approach_name} (Non-optimal)`}
                        >
                          {content}
                        </Collapsible>
                      );
                    })}
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      </div>

      {/* Right panel - Editor and test results */}
      <div className="w-1/2 flex flex-col">
        {/* Tabs header */}
        <div className="px-4 pt-2 border-b border-[var(--border)] flex items-center justify-between">
          <div className="flex gap-1">
            <button
              onClick={() => setRightTab("code")}
              className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
                rightTab === "code"
                  ? "border-[var(--primary)] text-[var(--foreground)]"
                  : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
              }`}
            >
              <Code className="h-4 w-4" />
              Code
            </button>
            {hasRunTests && (
              <button
                onClick={() => setRightTab("results")}
                className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
                  rightTab === "results"
                    ? "border-[var(--primary)] text-[var(--foreground)]"
                    : "border-transparent text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
                }`}
              >
                <FileText className="h-4 w-4" />
                Results
              </button>
            )}
          </div>
          <button
            onClick={handleReset}
            className="text-xs text-[var(--muted-foreground)] hover:text-[var(--foreground)] px-2 py-1"
          >
            Reset
          </button>
        </div>

        {/* Tab content */}
        <div className="flex-1 min-h-0 flex flex-col">
          {rightTab === "code" ? (
            <>
              {/* Editor - full height */}
              <div className="flex-1 min-h-0">
                <CodeEditor value={code} onChange={setCode} />
              </div>

              {/* Action buttons */}
              <div className="p-3 border-t border-[var(--border)] flex items-center justify-between bg-[var(--secondary)]">
                <div className="text-sm text-[var(--muted-foreground)]">
                  {pyodideLoading ? (
                    <span className="flex items-center gap-2">
                      <Loader2 className="h-4 w-4 animate-spin" />
                      Loading Python...
                    </span>
                  ) : (
                    "Python ready"
                  )}
                </div>
                <div className="flex gap-2">
                  <button
                    onClick={handleRunTests}
                    disabled={pyodideLoading || isLoading}
                    className="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded bg-[var(--secondary)] border border-[var(--border)] hover:bg-[var(--accent)] disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    {isRunning ? (
                      <Loader2 className="h-4 w-4 animate-spin" />
                    ) : (
                      <Play className="h-4 w-4" />
                    )}
                    Run Tests
                  </button>
                  <button
                    onClick={handleSubmit}
                    disabled={pyodideLoading || isLoading}
                    className="flex items-center gap-2 px-4 py-2 text-sm font-medium rounded bg-[var(--primary)] text-[var(--primary-foreground)] hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    {isSubmitting ? (
                      <Loader2 className="h-4 w-4 animate-spin" />
                    ) : (
                      <Send className="h-4 w-4" />
                    )}
                    Submit
                  </button>
                </div>
              </div>
            </>
          ) : (
            /* Results tab */
            <div className="flex-1 overflow-auto p-4">
              <TestResults
                visibleResults={visibleResults}
                hiddenPassedCount={hiddenPassedCount}
                hiddenTotalCount={hiddenTotalCount}
                visibleTestCases={visibleTestCases}
              />
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
