import * as React from 'react'
import { EditorView, lineNumbers as cmLineNumbers } from '@codemirror/view'
import { EditorState, type Extension } from '@codemirror/state'
import { HighlightStyle, syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language'
import { tags as t } from '@lezer/highlight'
import { CheckIcon, CopyIcon } from 'lucide-react'

import { cn } from './utils'

// Language imports
import { fluxl } from '../../editors/languages/fluxl'
import { yaral } from '../../editors/languages/yaral'
import { yara } from '../../editors/languages/yara'
import { sql } from '../../editors/languages/sql'
import { json } from '../../editors/languages/json'
import { yaml } from '../../editors/languages/yaml'
import { python } from '../../editors/languages/python'
import { javascript, typescript } from '../../editors/languages/javascript'
import { rust } from '../../editors/languages/rust'
import { markdown } from '../../editors/languages/markdown'
import { shellLanguage } from '../../editors/languages/shell'

// ---------------------------------------------------------------------------
// Theme (mirrors base.ts tfHighlightStyle + editorTheme for read-only view)
// ---------------------------------------------------------------------------

const viewerHighlightStyle = HighlightStyle.define([
  { tag: t.keyword, color: 'var(--cmm-editor-keyword, #7c3aed)' },
  { tag: t.operator, color: 'var(--cmm-editor-operator, #0891b2)' },
  { tag: [t.string, t.special(t.string)], color: 'var(--cmm-editor-string, #059669)' },
  { tag: t.number, color: 'var(--cmm-editor-number, #d97706)' },
  { tag: t.comment, color: 'var(--cmm-editor-comment, #6b7280)', fontStyle: 'italic' },
  { tag: t.variableName, color: 'var(--cmm-editor-variable, #1e40af)' },
  { tag: [t.function(t.variableName)], color: 'var(--cmm-editor-function, #2563eb)' },
  { tag: t.typeName, color: 'var(--cmm-editor-type, #0891b2)' },
  { tag: t.propertyName, color: 'var(--cmm-editor-property, #7c3aed)' },
  { tag: t.bool, color: 'var(--cmm-editor-atom, #d97706)' },
  { tag: t.null, color: 'var(--cmm-editor-atom, #d97706)' },
  { tag: t.atom, color: 'var(--cmm-editor-atom, #d97706)' },
  { tag: t.meta, color: 'var(--cmm-editor-meta, #6b7280)' },
  { tag: t.labelName, color: 'var(--cmm-editor-label, #2563eb)' },
  { tag: t.namespace, color: 'var(--cmm-editor-namespace, #0891b2)' },
  { tag: t.regexp, color: 'var(--cmm-editor-regexp, #dc2626)' },
  { tag: t.bracket, color: 'var(--cmm-editor-bracket, #6b7280)' },
  { tag: t.punctuation, color: 'var(--cmm-editor-punctuation, #6b7280)' },
  { tag: t.tagName, color: 'var(--cmm-editor-tag, #dc2626)' },
  { tag: t.attributeName, color: 'var(--cmm-editor-attribute, #d97706)' },
])

const viewerTheme = EditorView.theme({
  '&': {
    fontSize: '13px',
    backgroundColor: 'transparent',
    color: 'var(--cmm-text-primary, #e2e8f0)',
  },
  '&.cm-focused': {
    outline: 'none',
  },
  '.cm-content': {
    padding: '0',
    caretColor: 'transparent',
    fontFamily: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace",
  },
  '.cm-cursor': {
    display: 'none',
  },
  '.cm-gutters': {
    backgroundColor: 'transparent',
    color: 'var(--cmm-text-muted, #64748b)',
    borderRight: '1px solid var(--cmm-border, rgba(255,255,255,0.1))',
    fontFamily: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace",
    fontSize: '12px',
    minWidth: '3em',
  },
  '.cm-activeLineGutter': {
    backgroundColor: 'transparent',
  },
  '.cm-activeLine': {
    backgroundColor: 'transparent',
  },
  '.cm-line': {
    padding: '0 8px',
  },
  '.cm-scroller': {
    overflow: 'auto',
  },
  '&.cm-focused .cm-selectionBackground, .cm-selectionBackground': {
    backgroundColor: 'var(--cmm-editor-selection, rgba(59, 130, 246, 0.2))',
  },
})

// ---------------------------------------------------------------------------
// Language resolver
// ---------------------------------------------------------------------------

function resolveLanguage(language: string): Extension {
  switch (language.toLowerCase()) {
    case 'fluxl':
    case 'flux-l':
      return fluxl()
    case 'sql':
      return sql()
    case 'yaral':
    case 'yara-l':
    case 'yara_l':
      return yaral()
    case 'yara':
    case 'yara-x':
      return yara()
    case 'json':
      return json()
    case 'yaml':
    case 'yml':
      return yaml()
    case 'python':
    case 'py':
      return python()
    case 'javascript':
    case 'js':
    case 'jsx':
      return javascript()
    case 'typescript':
    case 'ts':
    case 'tsx':
      return typescript()
    case 'rust':
    case 'rs':
      return rust()
    case 'markdown':
    case 'md':
      return markdown()
    case 'bash':
    case 'sh':
    case 'shell':
    case 'zsh':
      return shellLanguage()
    case 'sigma':
      // Sigma rules are YAML-based
      return yaml()
    case 'suricata':
    case 'snort':
      // No dedicated tokenizer yet — plain text
      return []
    default:
      return []
  }
}

// ---------------------------------------------------------------------------
// CodeViewer component
// ---------------------------------------------------------------------------

export interface CodeViewerProps extends Omit<React.ComponentProps<'div'>, 'onChange'> {
  /** The code string to display */
  code: string
  /** Language for syntax highlighting */
  language?: string
  /** Show line numbers (default: true) */
  showLineNumbers?: boolean
  /** Show copy-to-clipboard button (default: true) */
  showCopyButton?: boolean
  /** Language label shown in header (defaults to language prop) */
  languageLabel?: string
  /** Maximum height with overflow scroll */
  maxHeight?: string
  /** Word wrap long lines */
  wordWrap?: boolean
}

function CodeViewer({
  className,
  code,
  language = '',
  showLineNumbers = true,
  showCopyButton = true,
  languageLabel,
  maxHeight,
  wordWrap = false,
  ...props
}: CodeViewerProps) {
  const containerRef = React.useRef<HTMLDivElement>(null)
  const viewRef = React.useRef<EditorView | null>(null)
  const [copied, setCopied] = React.useState(false)
  const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)

  // Create / recreate editor when code or language changes
  React.useEffect(() => {
    if (!containerRef.current) return

    // Destroy previous view
    if (viewRef.current) {
      viewRef.current.destroy()
      viewRef.current = null
    }

    const extensions: Extension[] = [
      EditorState.readOnly.of(true),
      EditorView.editable.of(false),
      viewerTheme,
      syntaxHighlighting(viewerHighlightStyle),
      syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
    ]

    if (showLineNumbers) {
      extensions.push(cmLineNumbers())
    }

    if (wordWrap) {
      extensions.push(EditorView.lineWrapping)
    }

    const lang = resolveLanguage(language)
    if (lang) {
      extensions.push(lang)
    }

    const state = EditorState.create({
      doc: code,
      extensions,
    })

    viewRef.current = new EditorView({
      state,
      parent: containerRef.current,
    })

    return () => {
      if (viewRef.current) {
        viewRef.current.destroy()
        viewRef.current = null
      }
    }
  }, [code, language, showLineNumbers, wordWrap])

  // Copy handler
  const handleCopy = React.useCallback(() => {
    void navigator.clipboard.writeText(code).then(() => {
      setCopied(true)
      if (timeoutRef.current !== null) {
        clearTimeout(timeoutRef.current)
      }
      timeoutRef.current = setTimeout(() => {
        setCopied(false)
        timeoutRef.current = null
      }, 2000)
    })
  }, [code])

  React.useEffect(() => {
    return () => {
      if (timeoutRef.current !== null) {
        clearTimeout(timeoutRef.current)
      }
    }
  }, [])

  const displayLabel = languageLabel ?? language ?? ''

  return (
    <div
      data-slot="code-viewer"
      className={cn(
        'overflow-hidden rounded-xl border border-border-glass bg-surface-secondary/50 backdrop-blur-[20px]',
        className
      )}
      {...props}
    >
      {/* Header */}
      {(displayLabel || showCopyButton) && (
        <div className="flex items-center justify-between border-b border-border-glass px-4 py-2">
          <span className="text-xs font-medium text-foreground-muted">{displayLabel}</span>
          {showCopyButton && (
            <button
              type="button"
              aria-label="Copy code"
              onClick={handleCopy}
              className={cn(
                'inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-[11px] font-medium transition-colors',
                copied
                  ? 'text-accent-emerald'
                  : 'text-foreground-secondary hover:bg-glass-hover hover:text-foreground'
              )}
            >
              {copied ? <CheckIcon className="size-3.5" /> : <CopyIcon className="size-3.5" />}
              {copied ? 'Copied!' : 'Copy'}
            </button>
          )}
        </div>
      )}

      {/* CodeMirror container */}
      <div
        ref={containerRef}
        className="code-viewer-cm"
        style={maxHeight ? { maxHeight, overflow: 'auto' } : undefined}
      />
    </div>
  )
}

CodeViewer.displayName = 'CodeViewer'

export { CodeViewer }
