import { useCallback, useEffect, useRef, useState } from 'react'
import Editor, { type OnMount, type BeforeMount } from '@monaco-editor/react'
import type { editor as MonacoEditor } from 'monaco-editor'
import { useTreeEditorStore } from '@/store/treeEditorStore'
import { treeMarkdownApi } from '@/api/treeMarkdown'
import { resolutionFlowLanguage, LANGUAGE_ID } from './resolutionFlowLanguage'
import { resolutionFlowTheme, THEME_ID } from './resolutionFlowTheme'
import { createCompletionProvider } from './resolutionFlowCompletions'
import { CodeModeToolbar } from './CodeModeToolbar'
import { SyntaxHelpPanel } from './SyntaxHelpPanel'
import { setMonacoEditor } from './monacoEditorRef'
import { Spinner } from '@/components/common/Spinner'

export function CodeModeEditor() {
  const editorRef = useRef<MonacoEditor.IStandaloneCodeEditor | null>(null)
  const validationTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const abortControllerRef = useRef<AbortController | null>(null)

  const {
    markdownSource,
    markdownValidationErrors,
    isMarkdownValid,
    isValidating,
    setMarkdownSource,
    setMarkdownValidationResult,
    getAvailableTargetNodes,
  } = useTreeEditorStore()

  const [syntaxHelpOpen, setSyntaxHelpOpen] = useState(false)

  // Register language and theme before editor mounts
  const handleEditorWillMount: BeforeMount = useCallback((monaco) => {
    // Register language if not already registered
    const langs = monaco.languages.getLanguages()
    if (!langs.some((l: { id: string }) => l.id === LANGUAGE_ID)) {
      monaco.languages.register({ id: LANGUAGE_ID })
      monaco.languages.setMonarchTokensProvider(LANGUAGE_ID, resolutionFlowLanguage)
    }

    // Register theme
    monaco.editor.defineTheme(THEME_ID, resolutionFlowTheme)

    // Register completion provider
    monaco.languages.registerCompletionItemProvider(
      LANGUAGE_ID,
      createCompletionProvider(() =>
        getAvailableTargetNodes().map(n => ({
          id: n.id,
          label: n.label,
          type: n.type,
        }))
      )
    )
  }, [getAvailableTargetNodes])

  // Editor mounted
  const handleEditorDidMount: OnMount = useCallback((editor) => {
    editorRef.current = editor
    setMonacoEditor(editor)
    editor.focus()
  }, [])

  // Debounced validation on change
  const handleEditorChange = useCallback((value: string | undefined) => {
    const md = value ?? ''
    setMarkdownSource(md)

    // Cancel pending validation
    if (validationTimeoutRef.current) {
      clearTimeout(validationTimeoutRef.current)
    }
    if (abortControllerRef.current) {
      abortControllerRef.current.abort()
    }

    // Debounce 800ms
    validationTimeoutRef.current = setTimeout(async () => {
      abortControllerRef.current = new AbortController()
      try {
        const result = await treeMarkdownApi.validateMarkdown(md)
        setMarkdownValidationResult(result)

        // Set Monaco markers
        if (editorRef.current) {
          const monaco = (await import('monaco-editor')).default ?? await import('monaco-editor')
          const model = editorRef.current.getModel()
          if (model && monaco.editor?.setModelMarkers) {
            const markers = result.errors.map((err) => ({
              startLineNumber: err.line,
              startColumn: err.column,
              endLineNumber: err.line,
              endColumn: err.column + 1,
              message: err.message,
              severity: err.severity === 'error' ? 8 : 4, // MarkerSeverity.Error : Warning
            }))
            monaco.editor.setModelMarkers(model, 'resolutionflow', markers)
          }
        }
      } catch {
        // Validation cancelled or failed — ignore
      }
    }, 800)
  }, [setMarkdownSource, setMarkdownValidationResult])

  // Insert template at cursor
  const handleInsertTemplate = useCallback((template: string) => {
    const editor = editorRef.current
    if (!editor) return

    const position = editor.getPosition()
    if (!position) return

    const model = editor.getModel()
    if (!model) return

    // Insert at end of document
    const lastLine = model.getLineCount()
    const lastColumn = model.getLineMaxColumn(lastLine)

    editor.executeEdits('insert-template', [{
      range: {
        startLineNumber: lastLine,
        startColumn: lastColumn,
        endLineNumber: lastLine,
        endColumn: lastColumn,
      },
      text: template,
    }])

    // Move cursor to the inserted template
    const newLastLine = model.getLineCount()
    editor.setPosition({ lineNumber: newLastLine, column: 1 })
    editor.revealLine(newLastLine)
    editor.focus()
  }, [])

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      setMonacoEditor(null)
      if (validationTimeoutRef.current) {
        clearTimeout(validationTimeoutRef.current)
      }
      if (abortControllerRef.current) {
        abortControllerRef.current.abort()
      }
    }
  }, [])

  return (
    <div className="flex h-full flex-col">
      <CodeModeToolbar
        validationErrors={markdownValidationErrors}
        isValidating={isValidating}
        isValid={isMarkdownValid}
        onInsertTemplate={handleInsertTemplate}
        onToggleSyntaxHelp={() => setSyntaxHelpOpen(!syntaxHelpOpen)}
        syntaxHelpOpen={syntaxHelpOpen}
      />
      <div className="relative flex-1 min-h-0">
        <Editor
          height="100%"
          language={LANGUAGE_ID}
          theme={THEME_ID}
          value={markdownSource ?? ''}
          onChange={handleEditorChange}
          beforeMount={handleEditorWillMount}
          onMount={handleEditorDidMount}
          loading={
            <div className="flex h-full items-center justify-center bg-card">
              <Spinner size="sm" className="h-6 w-6 border-t-foreground" />
            </div>
          }
          options={{
            minimap: { enabled: false },
            fontSize: 13,
            lineNumbers: 'on',
            wordWrap: 'on',
            scrollBeyondLastLine: false,
            renderLineHighlight: 'line',
            tabSize: 2,
            insertSpaces: true,
            automaticLayout: true,
            suggestOnTriggerCharacters: true,
            quickSuggestions: true,
            padding: { top: 12, bottom: 12 },
            accessibilitySupport: 'on',
          }}
        />
        {/* Syntax help as absolute overlay on right side */}
        {syntaxHelpOpen && (
          <div className="absolute right-0 top-0 bottom-0 z-20 w-[280px]">
            <SyntaxHelpPanel open={syntaxHelpOpen} onClose={() => setSyntaxHelpOpen(false)} />
          </div>
        )}
      </div>
    </div>
  )
}
