'use client';

import { useState, useCallback, useEffect, useMemo } from 'react';
import { ChevronLeft, ChevronRight, FileText, Lightbulb, Image as ImageIcon } from 'lucide-react';
import { clsx } from 'clsx';
import { CodeEditor } from './CodeEditor';
import { ProblemList } from './ProblemList';
import { TestRunner } from './TestRunner';
import { AIHelper } from './AIHelper';
import { TASK_LABELS, CATEGORY_LABELS } from '@/config/constants';
import { extractCodeFromResponse, normalizeIndentation } from '@/lib/utils/response';
import type { CodingProblem, TestResult } from '@/types';

interface PracticeInterfaceProps {
  className?: string;
}

// State saved per problem
interface ProblemState {
  code: string;
  testResult: TestResult | null;
}

export function PracticeInterface({ className }: PracticeInterfaceProps) {
  const [selectedProblem, setSelectedProblem] = useState<CodingProblem | null>(null);
  const [userCode, setUserCode] = useState('');
  const [currentTestResult, setCurrentTestResult] = useState<TestResult | null>(null);

  // Store state per problem (code and test results)
  const [problemStates, setProblemStates] = useState<Map<string, ProblemState>>(new Map());

  const [solvedProblems, setSolvedProblems] = useState<Set<string>>(() => {
    if (typeof window !== 'undefined') {
      const stored = localStorage.getItem('solvedProblems');
      if (stored) {
        try {
          return new Set(JSON.parse(stored));
        } catch {
          return new Set();
        }
      }
    }
    return new Set();
  });

  const [isProblemListCollapsed, setIsProblemListCollapsed] = useState(false);
  const [isAIHelperCollapsed, setIsAIHelperCollapsed] = useState(true);
  const [problemListWidth, setProblemListWidth] = useState(320);
  const [aiHelperWidth, setAIHelperWidth] = useState(320);

  useEffect(() => {
    if (typeof window !== 'undefined') {
      localStorage.setItem('solvedProblems', JSON.stringify([...solvedProblems]));
    }
  }, [solvedProblems]);

  // Save current problem state when code changes
  useEffect(() => {
    if (selectedProblem && userCode) {
      setProblemStates(prev => {
        const newStates = new Map(prev);
        const existing = newStates.get(selectedProblem.id);
        newStates.set(selectedProblem.id, {
          code: userCode,
          testResult: existing?.testResult ?? currentTestResult,
        });
        return newStates;
      });
    }
  }, [selectedProblem, userCode]);

  // Extract code from question for function_completion problems
  const extractCodeFromQuestion = useCallback((question: string): { description: string; code: string | null } => {
    const codeBlockMatch = question.match(/```python\n([\s\S]*?)```/);
    if (codeBlockMatch) {
      // Remove the code block from the description
      const description = question.replace(/```python\n[\s\S]*?```/, '').trim();
      return { description, code: codeBlockMatch[1].trim() };
    }
    return { description: question, code: null };
  }, []);

  // Get display description (without code block for function_completion)
  const displayDescription = useMemo(() => {
    if (!selectedProblem) return '';
    if (selectedProblem.type === 'function_completion') {
      const { description } = extractCodeFromQuestion(selectedProblem.question);
      return description || 'Complete the function below:';
    }
    return selectedProblem.question;
  }, [selectedProblem, extractCodeFromQuestion]);

  // Get the function signature for function_completion problems
  // Returns imports + def line + docstring (everything before 'pass')
  const getFunctionSignature = useCallback((question: string): string | null => {
    const { code } = extractCodeFromQuestion(question);
    if (!code) return null;

    const lines = code.split('\n');
    const signatureLines: string[] = [];
    let foundDef = false;
    let inDocstring = false;
    let docstringChar = '';
    let docstringComplete = false;

    for (const line of lines) {
      const trimmed = line.trim();

      // Check if this is the def line
      if (!foundDef && trimmed.startsWith('def ')) {
        foundDef = true;
        signatureLines.push(line);
        continue;
      }

      // If we haven't found def yet, this is an import or other preamble - include it
      if (!foundDef) {
        signatureLines.push(line);
        continue;
      }

      // After def line, check for docstring
      if (!inDocstring && !docstringComplete && (line.includes('"""') || line.includes("'''"))) {
        signatureLines.push(line);
        docstringChar = line.includes('"""') ? '"""' : "'''";
        // Check if docstring starts and ends on same line
        const count = (line.match(new RegExp(docstringChar.replace(/"/g, '\\"'), 'g')) || []).length;
        if (count >= 2) {
          // Docstring complete on one line
          docstringComplete = true;
          continue;
        }
        inDocstring = true;
        continue;
      }

      // Check for docstring end (multi-line docstring)
      if (inDocstring && line.includes(docstringChar)) {
        signatureLines.push(line);
        inDocstring = false;
        docstringComplete = true;
        continue;
      }

      // Still inside multi-line docstring
      if (inDocstring) {
        signatureLines.push(line);
        continue;
      }

      // After docstring is complete, stop at 'pass' or any actual code
      if (docstringComplete || foundDef) {
        if (trimmed === 'pass' || trimmed === '' || trimmed.startsWith('#')) {
          // Skip 'pass', empty lines, and comments after docstring
          continue;
        }
        // Found actual implementation code - stop here
        break;
      }
    }

    return signatureLines.join('\n');
  }, [extractCodeFromQuestion]);

  const handleSelectProblem = useCallback((problem: CodingProblem) => {
    // Check if we have saved state for this problem
    const savedState = problemStates.get(problem.id);

    if (savedState) {
      // Restore saved code and test result
      setUserCode(savedState.code);
      setCurrentTestResult(savedState.testResult);
    } else {
      // Set initial code template based on problem type
      if (problem.type === 'function_completion') {
        const { code } = extractCodeFromQuestion(problem.question);
        if (code) {
          setUserCode(code + '\n    # Your code here\n    pass');
        } else {
          setUserCode('# Write your solution here\n');
        }
      } else {
        setUserCode('# Write your solution here\n');
      }
      // Reset test result for new problem
      setCurrentTestResult(null);
    }

    setSelectedProblem(problem);
  }, [extractCodeFromQuestion, problemStates]);

  const handleTestComplete = useCallback((result: TestResult) => {
    setCurrentTestResult(result);

    if (selectedProblem) {
      // Save test result to problem state
      setProblemStates(prev => {
        const newStates = new Map(prev);
        newStates.set(selectedProblem.id, {
          code: userCode,
          testResult: result,
        });
        return newStates;
      });

      if (result.passed) {
        setSolvedProblems((prev) => new Set([...prev, selectedProblem.id]));
      }
    }
  }, [selectedProblem, userCode]);

  const toggleAIHelper = useCallback(() => {
    setIsAIHelperCollapsed(prev => !prev);
  }, []);

  // Handler to apply code from AI Helper to the editor
  const handleApplyCode = useCallback((code: string) => {
    if (!selectedProblem) {
      setUserCode(code);
      return;
    }

    // Extract actual code from markdown code blocks if present
    const extractedCode = extractCodeFromResponse(code, selectedProblem.entryPoint);

    if (selectedProblem.type === 'function_completion') {
      // For function completion, combine the function signature with the generated body
      const signature = getFunctionSignature(selectedProblem.question);
      if (signature) {
        // Check if the AI response already includes the full function definition
        const hasFullFunction = extractedCode.match(/^\s*def\s+\w+\s*\(/m);

        if (hasFullFunction) {
          // AI returned full function - use it directly
          const normalized = normalizeIndentation(extractedCode, 0);
          setUserCode(normalized);
        } else {
          // AI returned only the body - combine with signature
          // Normalize the body code to have consistent 4-space indentation for function body
          const normalizedBody = normalizeIndentation(extractedCode, 4);
          setUserCode(signature + '\n' + normalizedBody);
        }
      } else {
        setUserCode(extractedCode);
      }
    } else {
      // For code generation, replace the entire code
      const normalized = normalizeIndentation(extractedCode, 0);
      setUserCode(normalized);
    }
  }, [selectedProblem, getFunctionSignature]);

  return (
    <div className={clsx('h-full flex overflow-hidden', className)}>
      {/* Problem List Sidebar */}
      <div
        className={clsx(
          'flex-shrink-0 transition-all duration-200 relative h-full',
          isProblemListCollapsed ? 'w-12' : ''
        )}
        style={{ width: isProblemListCollapsed ? 48 : problemListWidth }}
      >
        {isProblemListCollapsed ? (
          <div className="h-full flex flex-col items-center pt-4 bg-zinc-900/95 border-r border-zinc-800/80">
            <button
              onClick={() => setIsProblemListCollapsed(false)}
              className="p-2 rounded-md hover:bg-zinc-800/50 transition-colors"
              title="Expand problems"
            >
              <span className="text-xs text-zinc-500 [writing-mode:vertical-lr] font-medium">
                Problems
              </span>
            </button>
          </div>
        ) : (
          <>
            <ProblemList
              onSelectProblem={handleSelectProblem}
              selectedProblemId={selectedProblem?.id}
              solvedProblems={solvedProblems}
            />
            <button
              onClick={() => setIsProblemListCollapsed(true)}
              className="absolute -right-3 top-4 w-6 h-6 rounded-full bg-zinc-800 border border-zinc-700/50 flex items-center justify-center hover:bg-zinc-700 transition-colors z-50"
              title="Collapse problems"
            >
              <ChevronLeft className="w-4 h-4 text-zinc-400" />
            </button>
            <div
              className="absolute top-0 bottom-0 -right-0.5 w-1 cursor-col-resize hover:bg-teal-500/50 transition-colors z-40"
              onMouseDown={(e) => {
                e.preventDefault();
                const startX = e.clientX;
                const startWidth = problemListWidth;

                const handleMouseMove = (moveEvent: MouseEvent) => {
                  const newWidth = Math.min(500, Math.max(240, startWidth + moveEvent.clientX - startX));
                  setProblemListWidth(newWidth);
                };

                const handleMouseUp = () => {
                  document.removeEventListener('mousemove', handleMouseMove);
                  document.removeEventListener('mouseup', handleMouseUp);
                  document.body.style.cursor = '';
                  document.body.style.userSelect = '';
                };

                document.addEventListener('mousemove', handleMouseMove);
                document.addEventListener('mouseup', handleMouseUp);
                document.body.style.cursor = 'col-resize';
                document.body.style.userSelect = 'none';
              }}
            />
          </>
        )}
      </div>

      {/* Main Content */}
      <div className="flex-1 flex flex-col min-w-0 bg-zinc-950 h-full overflow-hidden">
        {selectedProblem ? (
          <>
            {/* Problem Description - compact header */}
            <div className="flex-shrink-0 border-b border-zinc-800/80 bg-zinc-900/50">
              <div className="px-4 py-3">
                <div className="flex items-center gap-2 mb-2 flex-wrap">
                  <span
                    className={clsx(
                      'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium border',
                      selectedProblem.type === 'function_completion'
                        ? 'bg-emerald-900/30 text-emerald-400 border-emerald-700/30'
                        : 'bg-blue-900/30 text-blue-400 border-blue-700/30'
                    )}
                  >
                    {TASK_LABELS[selectedProblem.type].label}
                  </span>
                  <span className="text-xs text-zinc-500">
                    {CATEGORY_LABELS[selectedProblem.category]}
                  </span>
                  {selectedProblem.hasImage && (
                    <span className="flex items-center gap-1 text-xs text-zinc-500">
                      <ImageIcon className="w-3.5 h-3.5" />
                      Has image
                    </span>
                  )}
                </div>
                <div className="flex items-start gap-4">
                  <div className="flex-1 min-w-0">
                    <p className="text-sm text-zinc-300 leading-relaxed">
                      {displayDescription}
                    </p>
                  </div>
                  {selectedProblem.imageUrl && (
                    <div className="flex-shrink-0">
                      <img
                        src={selectedProblem.imageUrl}
                        alt="Problem illustration"
                        className="max-w-[160px] max-h-24 rounded-lg border border-zinc-700/50 bg-zinc-900 object-contain"
                      />
                    </div>
                  )}
                </div>
              </div>
            </div>

            {/* Test Runner - at top, compact */}
            <div className="flex-shrink-0 border-b border-zinc-800/80">
              <TestRunner
                key={selectedProblem.id}
                userCode={userCode}
                testCode={selectedProblem.testCode}
                entryPoint={selectedProblem.entryPoint}
                onTestComplete={handleTestComplete}
                initialResult={currentTestResult}
              />
            </div>

            {/* Code Editor - takes remaining space */}
            <div className="flex-1 min-h-0">
              <CodeEditor
                value={userCode}
                onChange={setUserCode}
                language="python"
                height="calc(100vh - 220px)"
              />
            </div>
          </>
        ) : (
          <div className="flex-1 flex flex-col items-center justify-center text-center px-4">
            <div className="w-16 h-16 mb-5 rounded-xl bg-zinc-800/80 border border-teal-700/30 flex items-center justify-center">
              <FileText className="w-8 h-8 text-teal-400" />
            </div>
            <h2 className="text-xl font-semibold text-zinc-200 mb-2">
              Practice Mode
            </h2>
            <p className="text-zinc-500 max-w-md mb-6 text-sm leading-relaxed">
              Select a coding problem from the sidebar to start practicing.
              Solve problems and run unit tests to verify your solutions.
            </p>
            <div className="flex items-center gap-2 text-xs text-zinc-600">
              <Lightbulb className="w-4 h-4" />
              <span>Use the AI Helper for hints and guidance</span>
            </div>
          </div>
        )}
      </div>

      {/* AI Helper Sidebar */}
      <div
        className={clsx(
          'flex-shrink-0 transition-all duration-200 relative h-full'
        )}
        style={{ width: isAIHelperCollapsed ? 48 : aiHelperWidth }}
      >
        {!isAIHelperCollapsed && (
          <>
            <button
              onClick={toggleAIHelper}
              className="absolute -left-3 top-4 w-6 h-6 rounded-full bg-zinc-800 border border-zinc-700/50 flex items-center justify-center hover:bg-zinc-700 transition-colors z-50"
              title="Collapse AI Helper"
            >
              <ChevronRight className="w-4 h-4 text-zinc-400" />
            </button>
            <div
              className="absolute top-0 bottom-0 -left-0.5 w-1 cursor-col-resize hover:bg-teal-500/50 transition-colors z-40"
              onMouseDown={(e) => {
                e.preventDefault();
                const startX = e.clientX;
                const startWidth = aiHelperWidth;

                const handleMouseMove = (moveEvent: MouseEvent) => {
                  const newWidth = Math.min(500, Math.max(240, startWidth - (moveEvent.clientX - startX)));
                  setAIHelperWidth(newWidth);
                };

                const handleMouseUp = () => {
                  document.removeEventListener('mousemove', handleMouseMove);
                  document.removeEventListener('mouseup', handleMouseUp);
                  document.body.style.cursor = '';
                  document.body.style.userSelect = '';
                };

                document.addEventListener('mousemove', handleMouseMove);
                document.addEventListener('mouseup', handleMouseUp);
                document.body.style.cursor = 'col-resize';
                document.body.style.userSelect = 'none';
              }}
            />
          </>
        )}
        <AIHelper
          problem={selectedProblem}
          userCode={userCode}
          isCollapsed={isAIHelperCollapsed}
          onToggleCollapse={toggleAIHelper}
          onApplyCode={handleApplyCode}
        />
      </div>
    </div>
  );
}
