'use client';

import { useMemo, useState, useCallback } from 'react';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import { InlineMath, BlockMath } from 'react-katex';
import { Copy, Check, Play, Square, Edit2, X } from 'lucide-react';
import Editor from '@monaco-editor/react';
import { clsx } from 'clsx';
import { QubitIcon } from './QubitIcon';
import { ExecutionResult, ExecutionResultData } from './ExecutionResult';
import type { Message as MessageType } from '@/types';

interface MessageProps {
  message: MessageType;
  onCopyCode?: (code: string) => void;
  loadingStatus?: React.ReactNode;
}

// Custom matte dark theme - muted, professional colors
const customTheme: { [key: string]: React.CSSProperties } = {
  'code[class*="language-"]': {
    color: '#d4d4d8',
    background: 'none',
    fontFamily: "'JetBrains Mono', Consolas, Monaco, 'Andale Mono', monospace",
    fontSize: '0.875rem',
    textAlign: 'left',
    whiteSpace: 'pre',
    wordSpacing: 'normal',
    wordBreak: 'normal',
    wordWrap: 'normal',
    lineHeight: '1.6',
    tabSize: 4,
    hyphens: 'none',
  },
  'pre[class*="language-"]': {
    color: '#d4d4d8',
    background: '#18181b',
    fontFamily: "'JetBrains Mono', Consolas, Monaco, 'Andale Mono', monospace",
    fontSize: '0.875rem',
    textAlign: 'left',
    whiteSpace: 'pre',
    wordSpacing: 'normal',
    wordBreak: 'normal',
    wordWrap: 'normal',
    lineHeight: '1.6',
    tabSize: 4,
    hyphens: 'none',
    padding: '1rem',
    margin: '0',
    overflow: 'auto',
    borderRadius: '0.5rem',
  },
  comment: { color: '#71717a' },
  prolog: { color: '#71717a' },
  doctype: { color: '#71717a' },
  cdata: { color: '#71717a' },
  punctuation: { color: '#a1a1aa' },
  namespace: { opacity: 0.7 },
  property: { color: '#f0abfc' },
  tag: { color: '#f0abfc' },
  boolean: { color: '#c4b5fd' },
  number: { color: '#c4b5fd' },
  constant: { color: '#c4b5fd' },
  symbol: { color: '#c4b5fd' },
  deleted: { color: '#fca5a5' },
  selector: { color: '#86efac' },
  'attr-name': { color: '#fcd34d' },
  string: { color: '#86efac' },
  char: { color: '#86efac' },
  builtin: { color: '#86efac' },
  inserted: { color: '#86efac' },
  operator: { color: '#f0abfc' },
  entity: { color: '#fcd34d', cursor: 'help' },
  url: { color: '#67e8f9' },
  '.language-css .token.string': { color: '#67e8f9' },
  '.style .token.string': { color: '#67e8f9' },
  variable: { color: '#d4d4d8' },
  atrule: { color: '#93c5fd' },
  'attr-value': { color: '#86efac' },
  function: { color: '#93c5fd' },
  'class-name': { color: '#93c5fd' },
  keyword: { color: '#c4b5fd' },
  regex: { color: '#fcd34d' },
  important: { color: '#fcd34d', fontWeight: 'bold' },
  bold: { fontWeight: 'bold' },
  italic: { fontStyle: 'italic' },
};

function isPythonCode(language: string, code: string): boolean {
  if (language === 'python') return true;

  const pythonPatterns = [
    /^from\s+\w+\s+import/m,
    /^import\s+\w+/m,
    /^def\s+\w+\s*\(/m,
    /^class\s+\w+/m,
    /QuantumCircuit/,
    /qiskit/i,
  ];

  return pythonPatterns.some(p => p.test(code));
}

function CodeBlock({
  language,
  code: initialCode,
  onCopy,
}: {
  language: string;
  code: string;
  onCopy?: (code: string) => void;
}) {
  const [copied, setCopied] = useState(false);
  const [isExecuting, setIsExecuting] = useState(false);
  const [isEditing, setIsEditing] = useState(false);
  const [editedCode, setEditedCode] = useState(initialCode);
  const [executionResult, setExecutionResult] = useState<ExecutionResultData | null>(null);

  // The code to use (edited or original)
  const code = isEditing ? editedCode : initialCode;

  const handleCopy = async () => {
    await navigator.clipboard.writeText(code);
    setCopied(true);
    onCopy?.(code);
    setTimeout(() => setCopied(false), 2000);
  };

  const handleExecute = useCallback(async () => {
    if (isExecuting) return;

    setIsExecuting(true);
    setExecutionResult(null);

    try {
      const response = await fetch('/api/execute', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ code, timeout: 30 }),
      });

      const result = await response.json();
      setExecutionResult(result);
    } catch (error) {
      setExecutionResult({
        success: false,
        output: '',
        error: error instanceof Error ? error.message : 'Execution failed',
        executionTime: 0,
        hasCircuitOutput: false,
      });
    } finally {
      setIsExecuting(false);
    }
  }, [code, isExecuting]);

  const handleStopExecution = () => {
    setIsExecuting(false);
  };

  const handleToggleEdit = () => {
    if (isEditing) {
      // Exiting edit mode - keep the edited code
      setIsEditing(false);
    } else {
      // Entering edit mode
      setEditedCode(initialCode);
      setIsEditing(true);
    }
  };

  const handleCancelEdit = () => {
    setEditedCode(initialCode);
    setIsEditing(false);
  };

  const detectedLanguage = language || detectLanguage(code);
  const canExecute = isPythonCode(detectedLanguage, code);
  
  // Calculate editor height based on line count
  const lineCount = code.split('\n').length;
  const editorHeight = Math.min(Math.max(lineCount * 20 + 32, 100), 400);

  return (
    <div className="relative group my-3 code-block-wrapper">
      {/* Action buttons */}
      <div className="absolute right-2 top-2 flex items-center gap-1.5 opacity-0 group-hover:opacity-100 transition-opacity z-10">
        <span className="text-xs text-zinc-500 bg-zinc-800 px-2 py-0.5 rounded">
          {detectedLanguage || 'code'}
        </span>

        {/* Edit toggle */}
        <button
          onClick={isEditing ? handleCancelEdit : handleToggleEdit}
          className={clsx(
            'flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-all',
            isEditing
              ? 'bg-amber-600/20 text-amber-400 hover:bg-amber-600/30'
              : 'bg-zinc-700/50 text-zinc-400 hover:bg-zinc-700'
          )}
          title={isEditing ? 'Cancel editing' : 'Edit code'}
        >
          {isEditing ? (
            <>
              <X className="w-3 h-3" />
              <span>Cancel</span>
            </>
          ) : (
            <>
              <Edit2 className="w-3 h-3" />
              <span>Edit</span>
            </>
          )}
        </button>

        {canExecute && (
          <button
            onClick={isExecuting ? handleStopExecution : handleExecute}
            disabled={isExecuting}
            className={clsx(
              'flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-all',
              isExecuting
                ? 'bg-red-600/20 text-red-400 hover:bg-red-600/30'
                : 'bg-teal-600/20 text-teal-400 hover:bg-teal-600/30'
            )}
            title={isExecuting ? 'Stop execution' : 'Run code'}
          >
            {isExecuting ? (
              <>
                <Square className="w-3 h-3" />
                <span>Stop</span>
              </>
            ) : (
              <>
                <Play className="w-3 h-3" />
                <span>Run</span>
              </>
            )}
          </button>
        )}

        <button
          onClick={handleCopy}
          className="p-1.5 rounded bg-zinc-800 hover:bg-zinc-700 transition-colors"
          title="Copy code"
        >
          {copied ? (
            <Check className="w-3.5 h-3.5 text-emerald-400" />
          ) : (
            <Copy className="w-3.5 h-3.5 text-zinc-400" />
          )}
        </button>
      </div>

      {isEditing ? (
        // Monaco Editor for editing
        <div 
          className="rounded-lg overflow-hidden border border-amber-600/30"
          style={{ height: editorHeight }}
        >
          <Editor
            height="100%"
            language={detectedLanguage || 'python'}
            value={editedCode}
            onChange={(value) => setEditedCode(value || '')}
            theme="vs-dark"
            options={{
              fontSize: 14,
              fontFamily: "'JetBrains Mono', Consolas, Monaco, monospace",
              minimap: { enabled: false },
              scrollBeyondLastLine: false,
              lineNumbers: 'on',
              glyphMargin: false,
              folding: false,
              lineDecorationsWidth: 8,
              lineNumbersMinChars: 3,
              padding: { top: 12, bottom: 12 },
              renderLineHighlight: 'line',
              tabSize: 4,
              insertSpaces: true,
              wordWrap: 'on',
              automaticLayout: true,
            }}
          />
        </div>
      ) : (
        // Static code display
        <SyntaxHighlighter
          style={customTheme}
          language={detectedLanguage || 'python'}
          PreTag="div"
          customStyle={{
            margin: 0,
            borderRadius: '0.5rem',
            background: '#18181b',
            padding: '1rem',
            fontSize: '0.875rem',
            border: '1px solid #27272a',
            lineHeight: '1.6',
          }}
          codeTagProps={{
            style: {
              background: 'none',
              padding: 0,
            },
          }}
          wrapLongLines={false}
        >
          {code}
        </SyntaxHighlighter>
      )}

      {/* Execution result */}
      {(isExecuting || executionResult) && (
        <ExecutionResult
          result={executionResult || { success: false, output: '', error: '', executionTime: 0 }}
          isLoading={isExecuting}
        />
      )}
    </div>
  );
}

function detectLanguage(code: string): string {
  const pythonPatterns = [
    /^from\s+\w+\s+import/m,
    /^import\s+\w+/m,
    /^def\s+\w+\s*\(/m,
    /^class\s+\w+/m,
    /QuantumCircuit/,
    /qiskit/i,
    /\.measure/,
    /numpy|np\./,
    /print\s*\(/,
  ];

  if (pythonPatterns.some((p) => p.test(code))) {
    return 'python';
  }

  const jsPatterns = [
    /^const\s+\w+\s*=/m,
    /^let\s+\w+\s*=/m,
    /^function\s+\w+/m,
    /=>\s*{/,
    /console\.log/,
  ];

  if (jsPatterns.some((p) => p.test(code))) {
    return 'javascript';
  }

  const bashPatterns = [/^\$\s+/m, /^#!\/bin\/(ba)?sh/m, /\|\s*grep/, /apt-get|pip\s+install/];

  if (bashPatterns.some((p) => p.test(code))) {
    return 'bash';
  }

  return 'python';
}

function looksLikeCode(text: string): boolean {
  // Multi-line code indicators
  if (text.includes('\n')) {
    const codeIndicators = [
      /^from\s+/m,
      /^import\s+/m,
      /^def\s+/m,
      /^class\s+/m,
      /^\s*return\s+/m,
      /QuantumCircuit/,
      /Parameter\(/,
      /\.\w+\([^)]*\)/m, // Method calls like qc.h(), qc.cx()
    ];
    return codeIndicators.some((p) => p.test(text));
  }

  // Single-line code indicators for function completion responses
  const singleLinePatterns = [
    /^return\s+\w+/,                          // return circuit.control(...)
    /^\w+\s*=\s*\w+\([^)]*\)/,                // theta = Parameter("theta")
    /^\w+\.\w+\([^)]*\)$/,                    // circuit.control(num_ctrl_qubits)
    /\w+\s*=\s*\w+\([^)]*\)(?:\s+\w+\.|\s+\w+\s*=)/, // Multiple statements
    /QuantumCircuit\(/,
    /Parameter\(/,
    /\.control\(/,
    /\.measure\(/,
  ];
  return singleLinePatterns.some((p) => p.test(text.trim()));
}

export function Message({ message, onCopyCode, loadingStatus }: MessageProps) {
  const isUser = message.role === 'user';
  const isLoading = message.isLoading;

  const avatar = useMemo(() => {
    if (isUser) {
      return (
        <div className="w-8 h-8 rounded-md bg-zinc-800 flex items-center justify-center border border-zinc-700/50">
          <span className="text-[10px] font-bold text-zinc-400 font-mono">YOU</span>
        </div>
      );
    }
    return (
      <div className="w-8 h-8 rounded-md bg-zinc-800 flex items-center justify-center border border-teal-700/40">
        <QubitIcon size={18} className="text-teal-400" />
      </div>
    );
  }, [isUser]);

  const imageSource =
    message.imageUrl || (message.imageBase64 ? `data:image/jpeg;base64,${message.imageBase64}` : null);

  const processedContent = useMemo(() => {
    let content = message.content;

    // Convert non-standard math delimiters to standard LaTeX format
    // Display math: [ ... ] containing LaTeX → $$ ... $$
    content = content.replace(
      /\[\s*(\\[a-zA-Z][^\]]*)\s*\]/g,
      (match, inner) => `\n$$\n${inner.trim()}\n$$\n`
    );

    // Inline math with \(...\) → $...$
    content = content.replace(
      /\\\(([^)]+)\\\)/g,
      (match, inner) => `$${inner}$`
    );

    // Inline math: (expression) containing LaTeX → $...$
    // Match parentheses containing backslash commands but not nested parens
    content = content.replace(
      /\(([^()]*(?:\\[a-zA-Z{}^_]|\\frac|\\sqrt|\\sum|\\exp|\\left|\\right|\\bigl|\\bigr|\\Bigl|\\Bigr|\|[01]\\rangle)[^()]*)\)/g,
      (match, inner) => {
        // Only convert if it really looks like math
        if (/\\[a-zA-Z]/.test(inner) || /\|[01n]\\rangle/.test(inner)) {
          return `$${inner}$`;
        }
        return match;
      }
    );

    // Code detection for non-markdown responses
    if (!content.includes('```') && !content.includes('$$') && !content.includes('$') && looksLikeCode(content)) {
      content = content
        .replace(/(\w+\s*=\s*\w+\([^)]*\))\s+(\w+\.)/g, '$1\n$2')
        .replace(/(\w+\.[a-z_]+\([^)]*\))\s+(\w+\.)/g, '$1\n$2');

      content = '```python\n' + content + '\n```';
    }

    return content;
  }, [message.content]);

  return (
    <div className={clsx('flex gap-3 animate-in', isUser ? 'flex-row-reverse' : 'flex-row')}>
      <div className="flex-shrink-0">{avatar}</div>

      <div className={clsx('flex-1 max-w-[85%]', isUser ? 'flex flex-col items-end' : '')}>
        {imageSource && (
          <div className="mb-2 max-w-xs">
            <img
              src={imageSource}
              alt="Attached image"
              className="rounded-lg border border-zinc-700/50 max-h-64 object-contain bg-zinc-900"
            />
          </div>
        )}

        <div
          className={clsx(
            'rounded-xl px-4 py-3',
            isUser
              ? 'bg-teal-700/80 text-white rounded-tr-sm'
              : 'bg-zinc-800/90 border border-zinc-700/50 rounded-tl-sm'
          )}
        >
          {isLoading ? (
            loadingStatus || (
              <div className="typing-indicator py-1">
                <span />
                <span />
                <span />
              </div>
            )
          ) : (
            <div className={clsx('markdown-content', isUser && 'text-white/90')}>
              <ReactMarkdown
                remarkPlugins={[remarkMath]}
                rehypePlugins={[rehypeKatex]}
                components={{
                  code({ className, children, ...props }) {
                    const match = /language-(\w+)/.exec(className || '');
                    const code = String(children).replace(/\n$/, '');

                    // Check if this is a math block (from remark-math)
                    if (className === 'language-math' || className === 'math-inline') {
                      try {
                        return <InlineMath math={code} />;
                      } catch {
                        return <code className="text-red-400">{code}</code>;
                      }
                    }

                    const isBlock = match || code.includes('\n') || looksLikeCode(code);

                    if (isBlock) {
                      return <CodeBlock language={match?.[1] || ''} code={code} onCopy={onCopyCode} />;
                    }

                    return (
                      <code className={clsx('bg-zinc-700/50 px-1.5 py-0.5 rounded text-sm', className)} {...props}>
                        {children}
                      </code>
                    );
                  },
                  pre({ children }) {
                    return <>{children}</>;
                  },
                  // Handle math blocks from remark-math
                  span({ className, children, ...props }) {
                    if (className === 'math math-inline') {
                      try {
                        const math = String(children);
                        return <InlineMath math={math} />;
                      } catch {
                        return <span className="text-red-400">{children}</span>;
                      }
                    }
                    return <span className={className} {...props}>{children}</span>;
                  },
                  div({ className, children, ...props }) {
                    if (className === 'math math-display') {
                      try {
                        const math = String(children);
                        return <BlockMath math={math} />;
                      } catch {
                        return <div className="text-red-400">{children}</div>;
                      }
                    }
                    return <div className={className} {...props}>{children}</div>;
                  },
                }}
              >
                {processedContent}
              </ReactMarkdown>
            </div>
          )}
        </div>

        <span className="text-xs text-zinc-500 mt-1 px-2">
          {message.timestamp.toLocaleTimeString([], {
            hour: '2-digit',
            minute: '2-digit',
          })}
        </span>
      </div>
    </div>
  );
}
