import { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine, drawSelection, rectangularSelection, highlightSpecialChars } from '@codemirror/view'
import { EditorState, Compartment } from '@codemirror/state'
import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands'
import { syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldGutter, indentOnInput } from '@codemirror/language'
import { javascript } from '@codemirror/lang-javascript'
import { python } from '@codemirror/lang-python'
import { go } from '@codemirror/lang-go'
import { json } from '@codemirror/lang-json'
import { yaml } from '@codemirror/lang-yaml'
import { markdown } from '@codemirror/lang-markdown'
import { oneDark } from '@codemirror/theme-one-dark'
import { searchKeymap, highlightSelectionMatches } from '@codemirror/search'
import { closeBrackets, closeBracketsKeymap, autocompletion, completionKeymap } from '@codemirror/autocomplete'
import { X, Save, RotateCcw } from 'lucide-react'

const langExtensions = {
  javascript: () => javascript({ jsx: true }),
  typescript: () => javascript({ jsx: true, typescript: true }),
  python: () => python(),
  go: () => go(),
  json: () => json(),
  yaml: () => yaml(),
  markdown: () => markdown(),
}

function getLangExtension(lang) {
  const factory = langExtensions[lang]
  if (factory) return factory()
  return []
}

function createEditorTheme() {
  return EditorView.theme({
    '&': {
      fontSize: '13px',
      backgroundColor: 'var(--bg-base, #0F0D10)',
      color: 'var(--text-primary, #EAE0E2)',
      height: '100%',
    },
    '.cm-content': {
      fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
      caretColor: 'var(--accent, #FF0033)',
      padding: '4px 0',
    },
    '.cm-cursor': {
      borderLeftColor: 'var(--accent, #FF0033)',
      borderLeftWidth: '2px',
    },
    '&.cm-focused .cm-selectionBackground, .cm-selectionBackground': {
      backgroundColor: 'var(--accent-dim, #6B2033) !important',
    },
    '.cm-gutters': {
      backgroundColor: 'var(--bg-surface, #161218)',
      color: 'var(--text-tertiary, #8A7A7E)',
      border: 'none',
      borderRight: '1px solid var(--border, #2A1F22)',
    },
    '.cm-activeLineGutter': {
      backgroundColor: 'var(--bg-elevated, #1C1719)',
      color: 'var(--text-secondary, #D4C4C8)',
    },
    '.cm-activeLine': {
      backgroundColor: 'rgba(255, 0, 51, 0.05)',
    },
    '.cm-matchingBracket': {
      backgroundColor: 'var(--accent-dim, #6B2033)',
      outline: '1px solid var(--accent, #FF0033)',
      color: '#fff !important',
    },
    '.cm-selectionMatch': {
      backgroundColor: 'var(--accent-dim, #6B2033)',
    },
    '.cm-foldGutter': {
      color: 'var(--text-tertiary, #8A7A7E)',
    },
    '.cm-scroller': {
      overflow: 'auto',
    },
  }, { dark: true })
}

export default function FileEditor({ api, filePath, onClose }) {
  const editorRef = useRef(null)
  const viewRef = useRef(null)
  const langCompartment = useRef(new Compartment())
  const [content, setContent] = useState('')
  const [originalContent, setOriginalContent] = useState('')
  const [lang, setLang] = useState('text')
  const [dirty, setDirty] = useState(false)
  const [saving, setSaving] = useState(false)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [fileName, setFileName] = useState('')

  useEffect(() => {
    if (!filePath) return
    const name = filePath.split('/').pop()
    setFileName(name)

    api.fileRead(filePath).then(data => {
      setContent(data.content || '')
      setOriginalContent(data.content || '')
      setLang(data.lang || 'text')
      setLoading(false)
    }).catch(err => {
      setError(err.message || 'Failed to read file')
      setLoading(false)
    })
  }, [filePath])

  useEffect(() => {
    if (!editorRef.current || loading || viewRef.current) return

    const customTheme = createEditorTheme()

    const state = EditorState.create({
      doc: content,
      extensions: [
        customTheme,
        oneDark,
        lineNumbers(),
        highlightActiveLineGutter(),
        highlightSpecialChars(),
        history(),
        foldGutter(),
        drawSelection(),
        indentOnInput(),
        bracketMatching(),
        closeBrackets(),
        autocompletion(),
        rectangularSelection(),
        highlightActiveLine(),
        highlightSelectionMatches(),
        syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
        keymap.of([
          ...closeBracketsKeymap,
          ...defaultKeymap,
          ...searchKeymap,
          ...historyKeymap,
          ...completionKeymap,
          indentWithTab,
          {
            key: 'Mod-s',
            run: () => { handleSave() ; return true },
          },
          {
            key: 'Escape',
            run: () => { if (onClose) onClose() ; return true },
          },
        ]),
        langCompartment.current.of(getLangExtension(lang)),
        EditorView.updateListener.of(update => {
          if (update.docChanged) {
            const newContent = update.state.doc.toString()
            setDirty(newContent !== originalContent)
          }
        }),
        EditorView.lineWrapping,
      ],
    })

    const view = new EditorView({
      state,
      parent: editorRef.current,
    })

    viewRef.current = view

    return () => {
      view.destroy()
      viewRef.current = null
    }
  }, [loading])

  useEffect(() => {
    if (!viewRef.current || !lang) return
    try {
      viewRef.current.dispatch({
        effects: langCompartment.current.reconfigure(getLangExtension(lang)),
      })
    } catch {}
  }, [lang])

  const handleSave = useCallback(async () => {
    if (!viewRef.current || !filePath || saving) return
    const newContent = viewRef.current.state.doc.toString()
    setSaving(true)
    try {
      await api.fileWrite(filePath, newContent)
      setOriginalContent(newContent)
      setDirty(false)
      setContent(newContent)
    } catch (err) {
      setError(err.message)
    }
    setSaving(false)
  }, [filePath, saving, api])

  const handleReload = useCallback(() => {
    if (!viewRef.current) return
    api.fileRead(filePath).then(data => {
      const doc = data.content || ''
      viewRef.current.dispatch({
        changes: { from: 0, to: viewRef.current.state.doc.length, insert: doc },
      })
      setOriginalContent(doc)
      setDirty(false)
      setContent(doc)
      setLang(data.lang || 'text')
    }).catch(err => setError(err.message))
  }, [filePath, api])

  if (loading) {
    return (
      <div className="file-editor-panel">
        <div className="file-editor-header">
          <span className="file-editor-title">Loading...</span>
          <button className="ghost sm" onClick={onClose}><X size={14} /></button>
        </div>
      </div>
    )
  }

  if (error && !content) {
    return (
      <div className="file-editor-panel">
        <div className="file-editor-header">
          <span className="file-editor-title" style={{ color: 'var(--error)' }}>{error}</span>
          <button className="ghost sm" onClick={onClose}><X size={14} /></button>
        </div>
      </div>
    )
  }

  return (
    <div className="file-editor-panel">
      <div className="file-editor-header">
        <span className="file-editor-title">
          {fileName}
          {dirty && <span className="file-editor-dirty">●</span>}
        </span>
        <div className="file-editor-actions">
          <span className="file-editor-lang-badge">{lang}</span>
          <button className="ghost sm" onClick={handleReload} title="Reload">
            <RotateCcw size={13} />
          </button>
          <button
            className="sm primary"
            onClick={handleSave}
            disabled={!dirty || saving}
          >
            <Save size={13} />
            {saving ? '...' : 'Save'}
          </button>
          <button className="ghost sm" onClick={onClose}><X size={14} /></button>
        </div>
      </div>
      <div className="file-editor-body" ref={editorRef} />
    </div>
  )
}
