import { useState, useCallback, useEffect, useMemo } from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { tomorrowNightBlue } from '@uiw/codemirror-theme-tomorrow-night-blue';

// Language extensions
import { javascript } from '@codemirror/lang-javascript';
import { python } from '@codemirror/lang-python';
import { json } from '@codemirror/lang-json';
import { html } from '@codemirror/lang-html';
import { css } from '@codemirror/lang-css';
import { yaml } from '@codemirror/lang-yaml';
import { markdown } from '@codemirror/lang-markdown';
import { sql } from '@codemirror/lang-sql';
import { java } from '@codemirror/lang-java';
import { go } from '@codemirror/lang-go';
import { rust } from '@codemirror/lang-rust';
import { cpp } from '@codemirror/lang-cpp';
import { php } from '@codemirror/lang-php';
import { xml } from '@codemirror/lang-xml';
import { less } from '@codemirror/lang-less';
import { csharp } from '@replit/codemirror-lang-csharp';

import { WorkspaceMode } from '../lib/types';
import { socketClient } from '../lib/socket';

interface EditorPanelProps {
  workspaceMode: WorkspaceMode;
  filePath?: string;
  onCloseFile?: () => void;
}

interface EditorState {
  content: string;
  originalContent: string;
  isDirty: boolean;
  isLoading: boolean;
  isSaving: boolean;
  error?: string;
  language: string;
  successMessage?: string;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Extension = any;

/**
 * Map a language key to a CodeMirror language extension array.
 * Returns an empty array for unsupported types (plain text).
 */
function getLanguageExtensions(language: string): Extension[] {
  const extensionMap: Record<string, (() => Extension)[]> = {
    javascript: [() => javascript({ jsx: true })],
    typescript: [() => javascript({ jsx: true, typescript: true })],
    python: [() => python()],
    json: [() => json()],
    html: [() => html()],
    css: [() => css()],
    yaml: [() => yaml()],
    markdown: [() => markdown()],
    sql: [() => sql()],
    java: [() => java()],
    golang: [() => go()],
    rust: [() => rust()],
    c_cpp: [() => cpp()],
    csharp: [() => csharp()],
    php: [() => php()],
    xml: [() => xml()],
    less: [() => less()],
  };
  const factories = extensionMap[language];
  return factories ? factories.map(fn => fn()) : [];
}

/** Map file extension string to a language key used by getLanguageExtensions. */
function detectLanguage(filePath: string): string {
  const ext = filePath.split('.').pop()?.toLowerCase();
  const languageMap: Record<string, string> = {
    js: 'javascript',
    jsx: 'javascript',
    ts: 'typescript',
    tsx: 'typescript',
    py: 'python',
    java: 'java',
    c: 'c_cpp',
    cpp: 'c_cpp',
    h: 'c_cpp',
    hpp: 'c_cpp',
    cs: 'csharp',
    go: 'golang',
    rs: 'rust',
    php: 'php',
    html: 'html',
    htm: 'html',
    css: 'css',
    scss: 'css',       // CM6 has no official SCSS; CSS is close enough
    less: 'less',
    json: 'json',
    xml: 'xml',
    yaml: 'yaml',
    yml: 'yaml',
    md: 'markdown',
    sql: 'sql',
  };
  return languageMap[ext || ''] || 'text';
}

export default function EditorPanel({ workspaceMode, filePath, onCloseFile }: EditorPanelProps) {
  const [state, setState] = useState<EditorState>({
    content: '',
    originalContent: '',
    isDirty: false,
    isLoading: false,
    isSaving: false,
    language: 'text',
  });

  const isReadOnly = workspaceMode === WorkspaceMode.Agent;

  // Build extensions array from current language
  const extensions = useMemo(
    () => getLanguageExtensions(state.language),
    [state.language],
  );

  // Load file when filePath changes
  useEffect(() => {
    if (filePath) {
      loadFile(filePath);
    } else {
      setState({
        content: '',
        originalContent: '',
        isDirty: false,
        isLoading: false,
        isSaving: false,
        language: 'text',
      });
    }
  }, [filePath]);

  const loadFile = useCallback(async (path: string) => {
    setState(prev => ({ ...prev, isLoading: true, error: undefined }));

    try {
      const result = await socketClient.requestFileRead({ path });

      if (result.success && result.content !== undefined) {
        const language = detectLanguage(path);
        setState({
          content: result.content,
          originalContent: result.content,
          isDirty: false,
          isLoading: false,
          isSaving: false,
          language,
        });
      } else {
        setState(prev => ({
          ...prev,
          isLoading: false,
          error: result.error || 'Failed to load file',
        }));
      }
    } catch (error) {
      setState(prev => ({
        ...prev,
        isLoading: false,
        error: error instanceof Error ? error.message : 'Failed to load file',
      }));
    }
  }, []);

  const saveFile = useCallback(async () => {
    if (!filePath || isReadOnly) return;

    setState(prev => ({ ...prev, isSaving: true, error: undefined }));

    try {
      const result = await socketClient.requestFileWrite({
        path: filePath,
        content: state.content,
      });

      if (result.success) {
        setState(prev => ({
          ...prev,
          isSaving: false,
          originalContent: prev.content,
          isDirty: false,
          successMessage: 'File saved successfully',
        }));

        setTimeout(() => {
          setState(prev => ({ ...prev, successMessage: undefined }));
        }, 3000);
      } else {
        setState(prev => ({
          ...prev,
          isSaving: false,
          error: result.error || 'Failed to save file',
        }));
      }
    } catch (error) {
      setState(prev => ({
        ...prev,
        isSaving: false,
        error: error instanceof Error ? error.message : 'Failed to save file',
      }));
    }
  }, [filePath, state.content, isReadOnly]);

  const handleContentChange = useCallback((newValue: string) => {
    setState(prev => ({
      ...prev,
      content: newValue,
      isDirty: newValue !== prev.originalContent,
    }));
  }, []);

  const handleKeyDown = useCallback((e: KeyboardEvent) => {
    // Ctrl+S or Cmd+S to save
    if ((e.ctrlKey || e.metaKey) && e.key === 's') {
      e.preventDefault();
      if (!isReadOnly && state.isDirty) {
        saveFile();
      }
    }
  }, [saveFile, isReadOnly, state.isDirty]);

  useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [handleKeyDown]);

  // No file selected — show placeholder
  if (!filePath) {
    return (
      <div className="flex-1 flex items-center justify-center bg-bg-secondary">
        <div className="text-center text-text-muted">
          <svg className="w-16 h-16 mx-auto mb-4 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
          </svg>
          <p className="text-lg font-medium">No file open</p>
          <p className="text-sm mt-2">Select a file from the tree to edit</p>
        </div>
      </div>
    );
  }

  return (
    <div className="flex-1 flex flex-col bg-bg-secondary min-h-0">
      {/* Editor Header */}
      <div className="flex items-center justify-between px-4 py-2 bg-bg-tertiary border-b border-border-subtle">
        <div className="flex items-center gap-3 min-w-0">
          <span className="text-sm font-medium text-text-primary truncate">
            {filePath}
          </span>
          {state.isDirty && (
            <span className="flex items-center gap-1 text-xs text-yellow-500">
              <span className="w-2 h-2 rounded-full bg-yellow-500"></span>
              Unsaved changes
            </span>
          )}
          {state.successMessage && (
            <span className="text-xs text-green-500">
              {state.successMessage}
            </span>
          )}
        </div>

        <div className="flex items-center gap-2">
          {isReadOnly && (
            <span className="text-xs text-text-muted px-2 py-1 bg-bg-secondary rounded border border-border-default">
              Read-only (Agent mode)
            </span>
          )}

          <button
            onClick={saveFile}
            disabled={isReadOnly || !state.isDirty || state.isSaving}
            className={`px-3 py-1.5 text-xs font-medium rounded transition-colors ${
              isReadOnly || !state.isDirty || state.isSaving
                ? 'bg-bg-secondary text-text-muted cursor-not-allowed'
                : 'bg-brand text-white hover:bg-brand/80'
            }`}
          >
            {state.isSaving ? 'Saving...' : 'Save'}
          </button>

          {onCloseFile && (
            <button
              onClick={onCloseFile}
              className="p-1.5 text-text-muted hover:text-text-primary hover:bg-bg-secondary rounded transition-colors"
              title="Close file"
            >
              <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
              </svg>
            </button>
          )}
        </div>
      </div>

      {/* Error State */}
      {state.error && (
        <div className="px-4 py-3 bg-red-500/10 border-b border-red-500/20">
          <div className="flex items-start gap-2">
            <svg className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
            </svg>
            <div className="flex-1">
              <p className="text-sm text-red-500">{state.error}</p>
              <button
                onClick={() => loadFile(filePath)}
                className="mt-2 text-xs text-red-400 hover:text-red-300 underline"
              >
                Retry
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Loading State */}
      {state.isLoading && (
        <div className="flex-1 flex items-center justify-center">
          <div className="text-center">
            <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-brand mx-auto"></div>
            <p className="text-sm text-text-muted mt-4">Loading file...</p>
          </div>
        </div>
      )}

      {/* CodeMirror Editor */}
      {!state.isLoading && (
        <div className="flex-1 min-h-0 cm-editor-container">
          <CodeMirror
            value={state.content}
            onChange={handleContentChange}
            extensions={extensions}
            theme={tomorrowNightBlue}
            editable={!isReadOnly}
            basicSetup={{
              lineNumbers: true,
              highlightActiveLine: true,
              highlightActiveLineGutter: true,
              foldGutter: true,
              indentOnInput: true,
              bracketMatching: true,
              closeBrackets: true,
              autocompletion: false,
              tabSize: 2,
            }}
            style={{ height: '100%', fontSize: '14px' }}
          />
        </div>
      )}
    </div>
  );
}
