import React, { useEffect, useRef, useCallback, useState } from 'react'
import { useTabStore } from '../../stores/tabStore'
import { useSearchStore } from '../../stores/searchStore'
import { findMatches, buildLineStarts, getLineNumber } from '../../lib/searchEngine'

export function Editor() {
  const textareaRef = useRef<HTMLTextAreaElement>(null)
  const lineNumbersRef = useRef<HTMLDivElement>(null)
  const wrapperRef = useRef<HTMLDivElement>(null)
  const highlightRef = useRef<HTMLDivElement | null>(null)

  const activeTabId = useTabStore(s => s.activeTabId)
  const tabs = useTabStore(s => s.tabs)
  const activeTab = tabs.find(t => t.id === activeTabId) ?? null
  const getActiveTab = useTabStore(s => s.getActiveTab)
  const updateTabContent = useTabStore(s => s.updateTabContent)
  const setModified = useTabStore(s => s.setModified)

  // 搜索状态
  const searchIsVisible = useSearchStore(s => s.isVisible)
  const searchText = useSearchStore(s => s.searchText)
  const searchMatches = useSearchStore(s => s.matches)
  const searchCurrentIndex = useSearchStore(s => s.currentIndex)
  const searchOptions = useSearchStore(s => s.options)

  const [lineCount, setLineCount] = useState(1)
  const [cursorPos, setCursorPos] = useState({ line: 1, col: 1 })
  const [fileSize, setFileSize] = useState('')
  const updateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // 行高
  const lineHeightRef = useRef(20.8)
  useEffect(() => {
    const textarea = textareaRef.current
    if (!textarea) return
    const style = getComputedStyle(textarea)
    const measure = document.createElement('div')
    measure.style.cssText = `position:absolute;visibility:hidden;font-family:${style.fontFamily};font-size:${style.fontSize};line-height:${style.lineHeight};white-space:pre;width:0;`
    measure.textContent = 'X'
    document.body.appendChild(measure)
    const singleHeight = measure.offsetHeight
    measure.textContent = 'X\nX'
    const doubleHeight = measure.offsetHeight
    document.body.removeChild(measure)
    lineHeightRef.current = doubleHeight - singleHeight || 20.8
  }, [])

  // 字符宽度
  const charWidthRef = useRef(8)
  useEffect(() => {
    const textarea = textareaRef.current
    if (!textarea) return
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    if (!ctx) return
    const style = getComputedStyle(textarea)
    ctx.font = `${style.fontSize} ${style.fontFamily}`
    charWidthRef.current = ctx.measureText('M').width
  }, [])

  // 加载标签内容
  useEffect(() => {
    const tab = getActiveTab()
    const textarea = textareaRef.current
    if (!tab || !textarea) return

    textarea.value = tab.content
    setLineCount((tab.content.match(/\n/g) || []).length + 1)
    const bytes = new Blob([tab.content]).size
    setFileSize(bytes < 1024 ? bytes + ' B' : bytes < 1048576 ? (bytes / 1024).toFixed(1) + ' KB' : (bytes / 1048576).toFixed(1) + ' MB')

    requestAnimationFrame(() => {
      textarea.scrollTop = tab.scrollTop
      textarea.scrollLeft = tab.scrollLeft
      textarea.setSelectionRange(tab.selectionStart, tab.selectionEnd)
      if (lineNumbersRef.current) lineNumbersRef.current.scrollTop = tab.scrollTop
    })
  }, [activeTabId, getActiveTab])

  // 更新行号
  const updateLineNumbers = useCallback((content: string) => {
    setLineCount((content.match(/\n/g) || []).length + 1)
  }, [])

  // 输入事件
  const handleInput = useCallback(() => {
    const textarea = textareaRef.current
    const tab = getActiveTab()
    if (!textarea || !tab) return
    const content = textarea.value
    updateTabContent(tab.id, content)
    setModified(tab.id, true)
    updateLineNumbers(content)
    const bytes = new Blob([content]).size
    setFileSize(bytes < 1024 ? bytes + ' B' : bytes < 1048576 ? (bytes / 1024).toFixed(1) + ' KB' : (bytes / 1048576).toFixed(1) + ' MB')
  }, [getActiveTab, updateTabContent, setModified, updateLineNumbers])

  // 滚动同步
  const handleScroll = useCallback(() => {
    const textarea = textareaRef.current
    if (!textarea) return
    if (lineNumbersRef.current) {
      lineNumbersRef.current.scrollTop = textarea.scrollTop
    }
    // 更新搜索高亮位置
    if (highlightRef.current) {
      highlightRef.current.style.top = -textarea.scrollTop + 'px'
    }
    const maxScroll = textarea.scrollHeight - textarea.clientHeight
    const ratio = maxScroll > 0 ? textarea.scrollTop / maxScroll : 0
    window.dispatchEvent(new CustomEvent('editor-scroll', { detail: { ratio } }))
  }, [])

  // 搜索：执行搜索并更新 matches
  const activeContent = activeTab?.content
  useEffect(() => {
    if (!searchIsVisible || !searchText) {
      if (highlightRef.current) highlightRef.current.innerHTML = ''
      return
    }
    const textarea = textareaRef.current
    if (!textarea) return

    const matches = findMatches(textarea.value, searchText, searchOptions)
    useSearchStore.getState().setMatches(matches)
    renderHighlights(textarea.value, matches, searchCurrentIndex)
  }, [searchIsVisible, searchText, searchOptions, activeContent])

  // 搜索：currentIndex 变化时滚动到匹配位置
  useEffect(() => {
    if (searchCurrentIndex < 0 || searchMatches.length === 0) return
    const textarea = textareaRef.current
    if (!textarea) return

    const m = searchMatches[searchCurrentIndex]
    if (!m) return

    // 选中匹配文本
    textarea.focus()
    textarea.setSelectionRange(m.start, m.end)

    // 滚动到匹配位置
    const lineStarts = buildLineStarts(textarea.value)
    const line = getLineNumber(lineStarts, m.start)
    const lineHeight = lineHeightRef.current
    const matchTop = line * lineHeight
    const viewTop = textarea.scrollTop
    const viewBottom = viewTop + textarea.clientHeight
    if (matchTop < viewTop + 40 || matchTop > viewBottom - 40) {
      textarea.scrollTop = matchTop - textarea.clientHeight / 2
    }

    // 重新渲染高亮
    renderHighlights(textarea.value, searchMatches, searchCurrentIndex)
  }, [searchCurrentIndex, searchMatches])

  // 渲染搜索高亮 overlay
  const renderHighlights = useCallback((content: string, matches: Array<{start: number; end: number}>, currentIndex: number) => {
    const wrapper = wrapperRef.current
    const textarea = textareaRef.current
    if (!wrapper || !textarea) return

    // 创建或复用 overlay
    if (!highlightRef.current) {
      const overlay = document.createElement('div')
      overlay.id = 'search-highlights'
      overlay.style.cssText = 'position:absolute;top:0;left:0;right:0;height:' + textarea.scrollHeight + 'px;pointer-events:none;overflow:visible;z-index:1;'
      wrapper.style.position = 'relative'
      wrapper.appendChild(overlay)
      highlightRef.current = overlay
    }

    const overlay = highlightRef.current
    overlay.style.top = -textarea.scrollTop + 'px'
    overlay.style.height = textarea.scrollHeight + 'px'
    overlay.innerHTML = ''

    if (matches.length === 0) return

    const style = getComputedStyle(textarea)
    const paddingTop = parseFloat(style.paddingTop)
    const paddingLeft = parseFloat(style.paddingLeft)
    const lineHeight = lineHeightRef.current
    const charWidth = charWidthRef.current
    const lineStarts = buildLineStarts(content)

    for (let i = 0; i < matches.length; i++) {
      const m = matches[i]
      const startLine = getLineNumber(lineStarts, m.start)
      const startCol = m.start - lineStarts[startLine]
      const endLine = getLineNumber(lineStarts, m.end)
      const endCol = m.end - lineStarts[endLine]

      if (startLine === endLine) {
        // 单行匹配
        const div = document.createElement('div')
        div.className = 'search-hl' + (i === currentIndex ? ' current' : '')
        div.style.cssText = `position:absolute;top:${startLine * lineHeight + paddingTop}px;left:${startCol * charWidth + paddingLeft}px;height:${lineHeight}px;width:${Math.max((endCol - startCol) * charWidth, 8)}px;`
        overlay.appendChild(div)
      } else {
        // 多行匹配：第一行
        const div1 = document.createElement('div')
        div1.className = 'search-hl' + (i === currentIndex ? ' current' : '')
        const firstLineWidth = textarea.clientWidth - (startCol * charWidth + paddingLeft) - 20
        div1.style.cssText = `position:absolute;top:${startLine * lineHeight + paddingTop}px;left:${startCol * charWidth + paddingLeft}px;height:${lineHeight}px;width:${firstLineWidth}px;`
        overlay.appendChild(div1)

        // 中间行
        for (let l = startLine + 1; l < endLine; l++) {
          const divM = document.createElement('div')
          divM.className = 'search-hl' + (i === currentIndex ? ' current' : '')
          divM.style.cssText = `position:absolute;top:${l * lineHeight + paddingTop}px;left:${paddingLeft}px;height:${lineHeight}px;width:${textarea.clientWidth - paddingLeft * 2}px;`
          overlay.appendChild(divM)
        }

        // 最后一行
        const div2 = document.createElement('div')
        div2.className = 'search-hl' + (i === currentIndex ? ' current' : '')
        div2.style.cssText = `position:absolute;top:${endLine * lineHeight + paddingTop}px;left:${paddingLeft}px;height:${lineHeight}px;width:${endCol * charWidth}px;`
        overlay.appendChild(div2)
      }
    }
  }, [])

  // Tab 键
  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
    if (e.key === 'Tab') {
      e.preventDefault()
      const textarea = textareaRef.current
      if (!textarea) return
      const start = textarea.selectionStart
      const end = textarea.selectionEnd
      if (start !== end) {
        const lines = textarea.value.substring(start, end).split('\n')
        const indented = lines.map(line => '    ' + line).join('\n')
        document.execCommand('insertText', false, indented)
      } else {
        document.execCommand('insertText', false, '    ')
      }
    }
    if (e.key === 'Enter' && searchIsVisible) {
      e.preventDefault()
      const state = useSearchStore.getState()
      if (e.shiftKey) state.findPrev()
      else state.findNext()
    }
  }, [searchIsVisible])

  // 更新光标位置
  const updateCursorPos = useCallback(() => {
    const textarea = textareaRef.current
    if (!textarea) return
    const text = textarea.value
    const pos = textarea.selectionStart
    const textBefore = text.substring(0, pos)
    const lines = textBefore.split('\n')
    setCursorPos({ line: lines.length, col: lines[lines.length - 1].length + 1 })
  }, [])

  // 渲染行号
  const renderLineNumbers = () => {
    const lineHeight = lineHeightRef.current
    return Array.from({ length: lineCount }, (_, i) => (
      <div key={i} className="line-num" style={{ height: lineHeight }}>
        {i + 1}
      </div>
    ))
  }

  // 清理 overlay
  useEffect(() => {
    return () => {
      if (highlightRef.current) {
        highlightRef.current.remove()
        highlightRef.current = null
      }
    }
  }, [])

  return (
    <div id="editor-wrapper" ref={wrapperRef}>
      <div id="line-numbers" ref={lineNumbersRef}>
        {renderLineNumbers()}
      </div>
      <textarea
        ref={textareaRef}
        id="editor"
        spellCheck={false}
        placeholder="在此输入 Markdown 内容，或拖拽 .md 文件到窗口打开..."
        onInput={handleInput}
        onScroll={handleScroll}
        onClick={updateCursorPos}
        onKeyUp={updateCursorPos}
        onKeyDown={handleKeyDown}
      />
    </div>
  )
}
