class HighlightRenderer {
  constructor() {
    this.activeHighlights = new Map()
    this.currentIndex = -1
    console.log('🎨 HighlightRenderer: initialized')
  }

  renderAll(results) {
    try {
      if (!Array.isArray(results)) {
        console.error('❌ HighlightRenderer.renderAll: results must be an array')
        return 0
      }

      console.log(`🎨 HighlightRenderer.renderAll: starting to render ${results.length} highlights`)

      this.clearAll()

      let successCount = 0

      results.forEach((result, index) => {
        try {
          const highlight = this.createHighlight(result, index)
          if (highlight) {
            this.activeHighlights.set(highlight.id, highlight)
            successCount++
          }
        } catch (error) {
          console.warn(`⚠️ HighlightRenderer.renderAll: failed to create highlight at index ${index}`, error)
        }
      })

      console.log(`✅ HighlightRenderer.renderAll: successfully rendered ${successCount}/${results.length} highlights`)

      if (successCount > 0) {
        setTimeout(() => {
          this.navigateTo(0)
        }, 100)
      }

      return successCount

    } catch (error) {
      console.error('❌ HighlightRenderer.renderAll: fatal error', error)
      return 0
    }
  }

  createHighlight(result, index) {
    try {
      if (!result || !result.originalData) {
        console.warn('⚠️ HighlightRenderer.createHighlight: invalid result or missing originalData')
        return null
      }

      const type = result.originalData.type?.toLowerCase()

      switch (type) {
        case 'pdf':
        case 'pdf-page':
        case 'pdf-text':
        case 'pdf-fallback':
        case 'pdf-iframe-body':
          return this.createPdfHighlight(result, index)

        case 'table':
        case 'header-cell':
        case 'data-cell':
          return this.createTableHighlight(result, index)

        default:
          return this.createDomHighlight(result, index)
      }

    } catch (error) {
      console.error(`❌ HighlightRenderer.createHighlight: error at index ${index}`, error)
      return null
    }
  }

  createDomHighlight(result, index) {
    try {
      const location = result.location || {}
      const element = location.element || result.originalData?.element
      const matchedText = result.matchedText || ''

      if (!element || !matchedText) {
        console.warn('⚠️ HighlightRenderer.createDomHighlight: missing element or matchedText')
        return null
      }

      const textNodes = this.findTextNodes(element, matchedText)

      let targetNode = null
      if (textNodes.length > 0) {
        targetNode = textNodes[0]
      } else {
        const fuzzyNodes = this.findTextNodesFuzzy(element, matchedText)
        if (fuzzyNodes.length > 0) {
          targetNode = fuzzyNodes[0]
        }
      }

      if (!targetNode) {
        console.warn('⚠️ HighlightRenderer.createDomHighlight: could not find text node for:', matchedText.substring(0, 50))
        return null
      }

      const highlight = this.createMarkForNode(targetNode, matchedText, result.id, index, result)

      if (!highlight) {
        return null
      }

      console.log(`✅ HighlightRenderer.createDomHighlight: created highlight #${index + 1}`)
      return highlight

    } catch (error) {
      console.error(`❌ HighlightRenderer.createDomHighlight: error creating highlight`, error)
      return null
    }
  }

  createMarkForNode(targetNode, searchText, id, index, result) {
    try {
      if (!targetNode || !searchText) {
        console.warn('⚠️ HighlightRenderer.createMarkForNode: invalid parameters')
        return null
      }

      const range = document.createRange()

      const nodeText = targetNode.textContent
      let startIndex = nodeText.indexOf(searchText)

      if (startIndex === -1) {
        const cleanedSearch = this.cleanText(searchText)
        const cleanedNode = this.cleanText(nodeText)
        startIndex = cleanedNode.indexOf(cleanedSearch)

        if (startIndex !== -1) {
          startIndex = this.fuzzyFind(nodeText, searchText)
        }
      }

      if (startIndex === -1) {
        console.warn('⚠️ HighlightRenderer.createMarkForNode: could not locate text in node')
        return null
      }

      range.setStart(targetNode, startIndex)
      range.setEnd(targetNode, startIndex + searchText.length)

      const mark = document.createElement('mark')
      mark.className = 'search-highlight'
      mark.setAttribute('data-highlight-id', id)
      mark.setAttribute('data-highlight-index', index.toString())

      mark.innerHTML = `
        <span class="highlight-label">${index + 1}</span>
        <span class="highlight-text">${range.toString()}</span>
      `

      try {
        range.surroundContents(mark)
      } catch (rangeError) {
        console.warn('⚠️ HighlightRenderer.createMarkForNode: surroundContents failed, using alternative method', rangeError)

        const fragment = range.extractContents()
        mark.appendChild(fragment)

        range.insertNode(mark)
      }

      mark.addEventListener('click', (e) => {
        e.preventDefault()
        e.stopPropagation()
        this.navigateTo(index)
      })

      const highlight = {
        id,
        index,
        element: mark,
        type: 'dom',
        originalNode: targetNode,
        searchText,
        scrollIntoView: () => {
          try {
            if (mark && mark.parentNode) {
              mark.scrollIntoView({ behavior: 'smooth', block: 'center' })
            }
          } catch (scrollError) {
            console.warn('⚠️ HighlightRenderer.scrollIntoView: DOM highlight scroll failed', scrollError)
          }
        },
        remove: () => {
          try {
            if (mark && mark.parentNode) {
              const parent = mark.parentNode
              while (mark.firstChild) {
                parent.insertBefore(mark.firstChild, mark)
              }
              parent.removeChild(mark)
              if (parent.normalize) {
                parent.normalize()
              }
            }
          } catch (removeError) {
            console.warn('⚠️ HighlightRenderer.remove: DOM highlight removal failed', removeError)
          }
        }
      }

      return highlight

    } catch (error) {
      console.error('❌ HighlightRenderer.createMarkForNode: error creating mark element', error)
      return null
    }
  }

  findTextNodes(rootElement, searchText) {
    try {
      if (!rootElement || !searchText) {
        return []
      }

      const matchedNodes = []

      const walker = document.createTreeWalker(
        rootElement,
        NodeFilter.SHOW_TEXT,
        {
          acceptNode: (node) => {
            if (!node.textContent || node.textContent.trim().length === 0) {
              return NodeFilter.FILTER_REJECT
            }

            if (node.parentElement &&
                (node.parentElement.tagName === 'MARK' ||
                 node.parentElement.closest('.search-highlight'))) {
              return NodeFilter.FILTER_REJECT
            }

            return NodeFilter.FILTER_ACCEPT
          }
        }
      )

      let node
      while ((node = walker.nextNode())) {
        if (node.textContent.includes(searchText)) {
          matchedNodes.push(node)
        }
      }

      return matchedNodes

    } catch (error) {
      console.error('❌ HighlightRenderer.findTextNodes: error finding text nodes', error)
      return []
    }
  }

  findTextNodesFuzzy(rootElement, searchText) {
    try {
      if (!rootElement || !searchText) {
        return []
      }

      const cleanedSearch = this.cleanText(searchText)
      if (!cleanedSearch || cleanedSearch.length < 2) {
        return []
      }

      const matchedNodes = []

      const walker = document.createTreeWalker(
        rootElement,
        NodeFilter.SHOW_TEXT,
        {
          acceptNode: (node) => {
            if (!node.textContent || node.textContent.trim().length === 0) {
              return NodeFilter.FILTER_REJECT
            }
            return NodeFilter.FILTER_ACCEPT
          }
        }
      )

      let node
      while ((node = walker.nextNode())) {
        const cleanedNode = this.cleanText(node.textContent)
        if (cleanedNode.includes(cleanedSearch)) {
          matchedNodes.push(node)
        }
      }

      return matchedNodes

    } catch (error) {
      console.error('❌ HighlightRenderer.findTextNodesFuzzy: error in fuzzy search', error)
      return []
    }
  }

  fuzzyFind(text, keyword) {
    try {
      if (!text || !keyword) {
        return -1
      }

      const cleanedText = this.cleanText(text)
      const cleanedKeyword = this.cleanText(keyword)

      const cleanedIndex = cleanedText.indexOf(cleanedKeyword)

      if (cleanedIndex === -1) {
        return -1
      }

      let originalIndex = 0
      let cleanedPosition = 0

      for (let i = 0; i < text.length && cleanedPosition < cleanedIndex; i++) {
        const char = text[i]
        if (this.isSignificantChar(char)) {
          cleanedPosition++
        }
        originalIndex = i + 1
      }

      return originalIndex

    } catch (error) {
      console.error('❌ HighlightRenderer.fuzzyFind: error in fuzzy matching', error)
      return -1
    }
  }

  isSignificantChar(char) {
    if (!char) return false
    const code = char.charCodeAt(0)
    return !(
      (code >= 0x2000 && code <= 0x206F) ||
      (code >= 0x3000 && code <= 0x303F) ||
      (code >= 0xFF00 && code <= 0xFFEF) ||
      char === ' ' ||
      char === '\t' ||
      char === '\n' ||
      char === '\r'
    )
  }

  cleanText(text) {
    if (!text || typeof text !== 'string') {
      return ''
    }

    return text
      .replace(/[\s\u00A0\u2000-\u206F\u2E80-\u9FFF\uFF00-\uFFEF\u3000-\u303F]+/g, '')
      .replace(/[.,;:!?'"()\[\]{}<>\/\\@#$%^&*+=|~`\-_]+/g, '')
      .toLowerCase()
  }

  createPdfHighlight(result, index) {
    try {
      const iframeSelectors = ['.pdf-iframe', 'iframe[src*="pdfjs"]']
      let iframe = null

      for (const selector of iframeSelectors) {
        iframe = document.querySelector(selector)
        if (iframe) break
      }

      if (!iframe) {
        console.warn('⚠️ HighlightRenderer.createPdfHighlight: PDF iframe not found')
        return null
      }

      let iframeDoc = null
      let iframeWindow = null

      try {
        iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
        iframeWindow = iframe.contentWindow
      } catch (crossOriginError) {
        console.warn('⚠️ HighlightRenderer.createPdfHighlight: cannot access PDF iframe (cross-origin restriction)', crossOriginError)
        return this.createPdfFallbackHighlight(result, index, iframe)
      }

      if (!iframeDoc || !iframeWindow) {
        console.warn('⚠️ HighlightRenderer.createPdfHighlight: iframe document or window not available')
        return null
      }

      const viewerContainer = iframeDoc.querySelector('#viewerContainer')
      if (!viewerContainer) {
        console.warn('⚠️ HighlightRenderer.createPdfHighlight: viewerContainer not found in PDF')
        return null
      }

      const page = result.originalData?.page || result.location?.originalLocation?.page || 1
      const pageElement = iframeDoc.querySelector(`[data-page-number="${page}"]`) ||
                         iframeDoc.querySelector(`.page[data-page="${page}"]`)

      const overlay = document.createElement('div')
      overlay.className = 'pdf-highlight-overlay'
      overlay.setAttribute('data-highlight-id', result.id)
      overlay.setAttribute('data-highlight-index', index.toString())

      Object.assign(overlay.style, {
        position: 'absolute',
        backgroundColor: 'rgba(255, 235, 59, 0.35)',
        border: '2px solid #ffc107',
        borderRadius: '4px',
        boxShadow: '0 2px 8px rgba(255, 193, 7, 0.4)',
        pointerEvents: 'auto',
        cursor: 'pointer',
        zIndex: '1000',
        transition: 'all 0.3s ease'
      })

      const rectInfo = result.location?.rect || result.location?.originalLocation?.rect

      if (rectInfo) {
        Object.assign(overlay.style, {
          left: `${rectInfo.left || 10}px`,
          top: `${rectInfo.top || 50}px`,
          width: `${rectInfo.width || 200}px`,
          height: `${rectInfo.height || 30}px`
        })
      } else {
        Object.assign(overlay.style, {
          left: '10px',
          top: `${50 + (index * 40)}px`,
          width: '200px',
          height: '30px'
        })
      }

      const badge = document.createElement('div')
      badge.className = 'pdf-highlight-badge'
      badge.textContent = (index + 1).toString()
      Object.assign(badge.style, {
        position: 'absolute',
        top: '-12px',
        right: '-12px',
        width: '24px',
        height: '24px',
        backgroundColor: '#ffc107',
        color: '#000',
        borderRadius: '50%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '12px',
        fontWeight: 'bold',
        boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
        zIndex: '1001'
      })

      overlay.appendChild(badge)

      overlay.addEventListener('click', (e) => {
        e.preventDefault()
        e.stopPropagation()
        this.navigateTo(index)
      })

      overlay.addEventListener('mouseenter', () => {
        overlay.style.backgroundColor = 'rgba(255, 235, 59, 0.55)'
        overlay.style.transform = 'scale(1.02)'
      })

      overlay.addEventListener('mouseleave', () => {
        overlay.style.backgroundColor = 'rgba(255, 235, 59, 0.35)'
        overlay.style.transform = 'scale(1)'
      })

      if (pageElement) {
        pageElement.appendChild(overlay)
      } else {
        viewerContainer.appendChild(overlay)
      }

      const highlight = {
        id: result.id,
        index,
        element: overlay,
        type: 'pdf',
        page,
        iframe,
        iframeDoc,
        scrollIntoView: () => {
          try {
            this.goToPdfPage(page)

            setTimeout(() => {
              if (overlay && overlay.scrollIntoView) {
                overlay.scrollIntoView({ behavior: 'smooth', block: 'center' })
              }
            }, 300)
          } catch (scrollError) {
            console.warn('⚠️ HighlightRenderer.scrollIntoView: PDF highlight scroll failed', scrollError)
          }
        },
        remove: () => {
          try {
            if (overlay && overlay.parentNode) {
              overlay.parentNode.removeChild(overlay)
            }
          } catch (removeError) {
            console.warn('⚠️ HighlightRenderer.remove: PDF highlight removal failed', removeError)
          }
        }
      }

      console.log(`✅ HighlightRenderer.createPdfHighlight: created PDF highlight #${index + 1} on page ${page}`)
      return highlight

    } catch (error) {
      console.error(`❌ HighlightRenderer.createPdfHighlight: error creating PDF highlight`, error)
      return null
    }
  }

  createPdfFallbackHighlight(result, index, iframe) {
    try {
      console.log('📍 HighlightRenderer.createPdfFallbackHighlight: creating fallback indicator')

      const fallbackIndicator = document.createElement('div')
      fallbackIndicator.className = 'pdf-highlight-fallback'
      fallbackIndicator.setAttribute('data-highlight-id', result.id)
      fallbackIndicator.setAttribute('data-highlight-index', index.toString())
      fallbackIndicator.innerHTML = `
        <span class="fallback-label">${index + 1}</span>
        <span class="fallback-text">PDF位置: 页${result.originalData?.page || '?'}</span>
      `

      Object.assign(fallbackIndicator.style, {
        padding: '8px 12px',
        margin: '4px 0',
        backgroundColor: 'rgba(255, 235, 59, 0.2)',
        borderLeft: '4px solid #ffc107',
        borderRadius: '4px',
        cursor: 'pointer',
        fontSize: '14px',
        color: '#333'
      })

      fallbackIndicator.addEventListener('click', (e) => {
        e.preventDefault()
        this.navigateTo(index)
      })

      const container = iframe?.parentElement || document.body
      container.insertBefore(fallbackIndicator, iframe?.nextSibling || null)

      const highlight = {
        id: result.id,
        index,
        element: fallbackIndicator,
        type: 'pdf-fallback',
        scrollIntoView: () => {
          try {
            fallbackIndicator.scrollIntoView({ behavior: 'smooth', block: 'center' })
          } catch (error) {
            console.warn('⚠️ HighlightRenderer.scrollIntoView: fallback scroll failed', error)
          }
        },
        remove: () => {
          try {
            if (fallbackIndicator.parentNode) {
              fallbackIndicator.parentNode.removeChild(fallbackIndicator)
            }
          } catch (error) {
            console.warn('⚠️ HighlightRenderer.remove: fallback removal failed', error)
          }
        }
      }

      return highlight

    } catch (error) {
      console.error('❌ HighlightRenderer.createPdfFallbackHighlight: error creating fallback', error)
      return null
    }
  }

  createTableHighlight(result, index) {
    try {
      const cell = result.originalData?.element || result.location?.element

      if (!cell || !(cell instanceof HTMLElement)) {
        console.warn('⚠️ HighlightRenderer.createTableHighlight: cell element not found')
        return null
      }

      cell.classList.add('table-highlight')
      cell.setAttribute('data-highlight-id', result.id)
      cell.setAttribute('data-highlight-index', index.toString())

      const currentStyle = window.getComputedStyle(cell).position
      if (currentStyle === 'static') {
        cell.style.position = 'relative'
      }

      const badge = document.createElement('div')
      badge.className = 'table-highlight-badge'
      badge.textContent = (index + 1).toString()

      Object.assign(badge.style, {
        position: 'absolute',
        top: '-8px',
        right: '-8px',
        width: '20px',
        height: '20px',
        backgroundColor: '#28a745',
        color: '#fff',
        borderRadius: '50%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '11px',
        fontWeight: 'bold',
        boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
        zIndex: '10',
        pointerEvents: 'none'
      })

      cell.appendChild(badge)

      cell.addEventListener('click', (e) => {
        e.preventDefault()
        e.stopPropagation()
        this.navigateTo(index)
      })

      this.pulseAnimation(cell, 'table-pulse')

      const highlight = {
        id: result.id,
        index,
        element: cell,
        type: 'table',
        badge,
        scrollIntoView: () => {
          try {
            cell.scrollIntoView({ behavior: 'smooth', block: 'center' })
          } catch (scrollError) {
            console.warn('⚠️ HighlightRenderer.scrollIntoView: table highlight scroll failed', scrollError)
          }
        },
        remove: () => {
          try {
            cell.classList.remove('table-highlight')
            cell.removeAttribute('data-highlight-id')
            cell.removeAttribute('data-highlight-index')

            if (badge && badge.parentNode === cell) {
              cell.removeChild(badge)
            }

            if (currentStyle === 'static') {
              cell.style.position = ''
            }
          } catch (removeError) {
            console.warn('⚠️ HighlightRenderer.remove: table highlight removal failed', removeError)
          }
        }
      }

      console.log(`✅ HighlightRenderer.createTableHighlight: created table highlight #${index + 1}`)
      return highlight

    } catch (error) {
      console.error(`❌ HighlightRenderer.createTableHighlight: error creating table highlight`, error)
      return null
    }
  }

  navigateTo(index) {
    try {
      const total = this.activeHighlights.size

      if (index < 0 || index >= total) {
        console.warn(`⚠️ HighlightRenderer.navigateTo: invalid index ${index}, total highlights: ${total}`)
        return false
      }

      if (this.currentIndex >= 0 && this.currentIndex < total) {
        const currentHighlight = this.getHighlightByIndex(this.currentIndex)
        if (currentHighlight && currentHighlight.element) {
          currentHighlight.element.classList.remove('active')
        }
      }

      this.currentIndex = index

      const targetHighlight = this.getHighlightByIndex(index)
      if (!targetHighlight || !targetHighlight.element) {
        console.error(`❌ HighlightRenderer.navigateTo: highlight not found at index ${index}`)
        return false
      }

      targetHighlight.element.classList.add('active')

      if (typeof targetHighlight.scrollIntoView === 'function') {
        targetHighlight.scrollIntoView()
      }

      this.dispatchEvent('highlightNavigate', {
        currentIndex: index,
        total: total,
        highlightId: targetHighlight.id
      })

      console.log(`📍 HighlightRenderer.navigateTo: navigated to highlight #${index + 1}/${total}`)
      return true

    } catch (error) {
      console.error('❌ HighlightRenderer.navigateTo: navigation error', error)
      return false
    }
  }

  next() {
    try {
      const total = this.activeHighlights.size

      if (this.currentIndex < total - 1) {
        return this.navigateTo(this.currentIndex + 1)
      } else {
        console.log('📍 HighlightRenderer.next: already at last highlight, cycling to first')
        return this.navigateTo(0)
      }
    } catch (error) {
      console.error('❌ HighlightRenderer.next: error navigating to next', error)
      return false
    }
  }

  prev() {
    try {
      const total = this.activeHighlights.size

      if (this.currentIndex > 0) {
        return this.navigateTo(this.currentIndex - 1)
      } else {
        console.log('📍 HighlightRenderer.prev: already at first highlight, cycling to last')
        return this.navigateTo(total - 1)
      }
    } catch (error) {
      console.error('❌ HighlightRenderer.prev: error navigating to previous', error)
      return false
    }
  }

  clearAll() {
    try {
      console.log(`🎨 HighlightRenderer.clearAll: clearing ${this.activeHighlights.size} highlights`)

      this.activeHighlights.forEach((highlight, id) => {
        try {
          if (highlight && typeof highlight.remove === 'function') {
            highlight.remove()
          }
        } catch (error) {
          console.warn(`⚠️ HighlightRenderer.clearAll: error removing highlight ${id}`, error)
        }
      })

      this.activeHighlights.clear()
      this.currentIndex = -1

      this.dispatchEvent('highlightCleared', { timestamp: Date.now() })

      console.log('✅ HighlightRenderer.clearAll: all highlights cleared successfully')

    } catch (error) {
      console.error('❌ HighlightRenderer.clearAll: error clearing highlights', error)
    }
  }

  pulseAnimation(element, animationName) {
    try {
      if (!element || typeof element.style === 'undefined') {
        return
      }

      element.style.animation = 'none'

      void element.offsetHeight

      element.style.animation = `${animationName} 0.6s ease-in-out`

      setTimeout(() => {
        if (element && element.style) {
          element.style.animation = ''
        }
      }, 600)

    } catch (error) {
      console.warn('⚠️ HighlightRenderer.pulseAnimation: animation error', error)
    }
  }

  goToPdfPage(pageNumber) {
    try {
      const iframeSelectors = ['.pdf-iframe', 'iframe[src*="pdfjs"]']
      let iframe = null

      for (const selector of iframeSelectors) {
        iframe = document.querySelector(selector)
        if (iframe) break
      }

      if (!iframe) {
        console.warn('⚠️ HighlightRenderer.goToPdfPage: PDF iframe not found')
        return false
      }

      try {
        const iframeWindow = iframe.contentWindow
        if (iframeWindow?.PDFViewerApplication?.pdfViewer) {
          iframeWindow.PDFViewerApplication.pdfViewer.currentPageNumber = pageNumber
          console.log(`📍 HighlightRenderer.goToPdfPage: navigated to page ${pageNumber}`)
          return true
        } else {
          console.warn('⚠️ HighlightRenderer.goToPdfPage: PDFViewerApplication not available')
          return false
        }
      } catch (crossOriginError) {
        console.warn('⚠️ HighlightRenderer.goToPdfPage: cannot access PDF iframe (cross-origin)', crossOriginError)
        return false
      }

    } catch (error) {
      console.error('❌ HighlightRenderer.goToPdfPage: error navigating to PDF page', error)
      return false
    }
  }

  getHighlightByIndex(index) {
    try {
      if (index < 0 || index >= this.activeHighlights.size) {
        return null
      }

      const highlightsArray = Array.from(this.activeHighlights.values())
      return highlightsArray[index]

    } catch (error) {
      console.error('❌ HighlightRenderer.getHighlightByIndex: error getting highlight', error)
      return null
    }
  }

  dispatchEvent(eventName, detail) {
    try {
      const event = new CustomEvent(eventName, {
        bubbles: true,
        cancelable: true,
        detail: detail
      })

      document.dispatchEvent(event)

    } catch (error) {
      console.warn(`⚠️ HighlightRenderer.dispatchEvent: error dispatching event "${eventName}"`, error)
    }
  }

  getTotalCount() {
    return this.activeHighlights.size
  }

  getCurrentIndex() {
    return this.currentIndex
  }

  getAllHighlights() {
    return Array.from(this.activeHighlights.values())
  }

  hasActiveHighlights() {
    return this.activeHighlights.size > 0
  }

  destroy() {
    try {
      this.clearAll()
      console.log('✅ HighlightRenderer: destroyed and cleaned up')
    } catch (error) {
      console.error('❌ HighlightRenderer.destroy: error during destruction', error)
    }
  }
}

export default new HighlightRenderer()
