class TextExtractor {
  constructor() {
    this.supportedTypes = ['pdf', 'docx', 'doc', 'xlsx', 'csv', 'pptx', 'text', 'markdown', 'code', 'json', 'xml', 'html']
  }

  async extract(fileType, container) {
    if (!container) {
      console.error('❌ TextExtractor: container is required')
      return []
    }

    const type = fileType?.toLowerCase()
    
    if (!this.supportedTypes.includes(type)) {
      console.warn(`⚠️ TextExtractor: unsupported file type "${type}", falling back to DOM extraction`)
      return this.extractDomText(container)
    }

    console.log(`📄 TextExtractor: extracting text from ${type.toUpperCase()} document`)

    try {
      let result = []

      switch (type) {
        case 'pdf':
          result = await this.extractPdfText(container)
          break
        case 'docx':
          result = await this.extractDocxText(container)
          break
        case 'doc':
          result = await this.extractDocText(container)
          break
        case 'xlsx':
        case 'csv':
          result = await this.extractExcelText(container)
          break
        case 'pptx':
          result = await this.extractPptxText(container)
          break
        case 'text':
          result = await this.extractPlainText(container)
          break
        case 'markdown':
        case 'code':
        case 'json':
        case 'xml':
        case 'html':
          result = await this.extractDomText(container)
          break
        default:
          result = await this.extractDomText(container)
      }

      console.log(`✅ TextExtractor: extracted ${result.length} text segments from ${type.toUpperCase()}`)
      return result

    } catch (error) {
      console.error(`❌ TextExtractor: error extracting text from ${type}`, error)
      console.warn('⚠️ TextExtractor: falling back to plain text extraction')
      return this.extractPlainText(container)
    }
  }

  async extractPdfText(container) {
    console.log('📄 TextExtractor: starting PDF text extraction')

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

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

      if (!iframe) {
        console.warn('⚠️ TextExtractor: PDF iframe not found, trying fallback')
        return this.extractPdfFallback(container)
      }

      const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
      if (!iframeDoc) {
        console.warn('⚠️ TextExtractor: cannot access iframe document')
        return this.extractPdfFallback(container)
      }

      const textLayer = iframeDoc.querySelector('.textLayer')
      if (!textLayer) {
        console.warn('⚠️ TextExtractor: .textLayer not found in PDF iframe')
        return this.extractPdfFromIframeBody(iframeDoc)
      }

      const pages = textLayer.querySelectorAll('[data-page]')
      const results = []

      if (pages.length > 0) {
        pages.forEach((page, index) => {
          const pageText = this.cleanText(page.textContent)
          if (pageText && pageText.length >= 2) {
            results.push({
              text: pageText,
              type: 'pdf-page',
              location: { page: index + 1 },
              element: page
            })
          }
        })
      } else {
        const brElements = textLayer.querySelectorAll('br')
        if (brElements.length > 0) {
          let currentPageText = ''
          let pageIndex = 0

          const allNodes = textLayer.childNodes
          allNodes.forEach(node => {
            if (node.nodeName === 'BR') {
              if (currentPageText.trim().length >= 2) {
                results.push({
                  text: currentPageText.trim(),
                  type: 'pdf-page',
                  location: { page: pageIndex + 1 },
                  element: textLayer
                })
              }
              currentPageText = ''
              pageIndex++
            } else if (node.nodeType === Node.TEXT_NODE) {
              currentPageText += node.textContent
            } else if (node.nodeType === Node.ELEMENT_NODE) {
              currentPageText += node.textContent
            }
          })

          if (currentPageText.trim().length >= 2) {
            results.push({
              text: currentPageText.trim(),
              type: 'pdf-page',
              location: { page: pageIndex + 1 },
              element: textLayer
            })
          }
        } else {
          const fullText = this.cleanText(textLayer.textContent)
          if (fullText) {
            results.push({
              text: fullText,
              type: 'pdf-text',
              element: textLayer
            })
          }
        }
      }

      console.log(`✅ TextExtractor: PDF extraction complete, found ${results.length} pages`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: PDF extraction failed', error)
      return this.extractPdfFallback(container)
    }
  }

  extractPdfFallback(container) {
    console.log('⚠️ TextExtractor: using PDF fallback - extracting body text')

    try {
      const bodyText = this.cleanText(container.textContent)
      if (!bodyText || bodyText.length < 2) {
        return []
      }

      return [{
        text: bodyText,
        type: 'pdf-fallback',
        element: container
      }]
    } catch (error) {
      console.error('❌ TextExtractor: PDF fallback also failed', error)
      return []
    }
  }

  extractPdfFromIframeBody(iframeDoc) {
    try {
      const bodyText = this.cleanText(iframeDoc.body?.textContent)
      if (!bodyText || bodyText.length < 2) {
        return []
      }

      return [{
        text: bodyText,
        type: 'pdf-iframe-body',
        element: iframeDoc.body
      }]
    } catch (error) {
      console.error('❌ TextExtractor: cannot extract from iframe body', error)
      return []
    }
  }

  async extractDocxText(container) {
    console.log('📄 TextExtractor: starting DOCX text extraction')

    try {
      const viewerSelectors = [
        '.docx-viewer',
        '.document-viewer',
        '[data-type="docx"]',
        '.word-document',
        '.docx-container'
      ]

      let viewer = null
      for (const selector of viewerSelectors) {
        viewer = container.querySelector(selector)
        if (viewer) break
      }

      if (!viewer) {
        console.warn('⚠️ TextExtractor: DOCX viewer not found, using fallback')
        return this.extractDomText(container)
      }

      const pageSelectors = [
        '.page',
        '.page-content',
        '[data-page]',
        '.document-page',
        '.word-page'
      ]

      let pages = []
      for (const selector of pageSelectors) {
        pages = viewer.querySelectorAll(selector)
        if (pages.length > 0) break
      }

      const results = []

      if (pages.length > 0) {
        pages.forEach((page, index) => {
          const pageText = this.cleanText(page.textContent)
          if (pageText && pageText.length >= 2) {
            results.push({
              page: index + 1,
              text: pageText,
              type: 'docx-page',
              element: page
            })
          }
        })
      } else {
        const fullText = this.cleanText(viewer.textContent)
        if (fullText) {
          results.push({
            page: 1,
            text: fullText,
            type: 'docx-full',
            element: viewer
          })
        }
      }

      console.log(`✅ TextExtractor: DOCX extraction complete, found ${results.length} pages`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: DOCX extraction failed', error)
      return this.extractDomText(container)
    }
  }

  async extractDocText(container) {
    console.log('📄 TextExtractor: starting DOC text extraction')

    try {
      const viewerSelectors = [
        '.doc-viewer',
        '.document-viewer',
        '[data-type="doc"]',
        '.word-document'
      ]

      let viewer = null
      for (const selector of viewerSelectors) {
        viewer = container.querySelector(selector)
        if (viewer) break
      }

      if (!viewer) {
        console.log('⚠️ TextExtractor: DOC viewer not found, treating as DOCX')
        return this.extractDocxText(container)
      }

      const pageDivs = viewer.querySelectorAll('.page, [data-page], .document-page')
      const results = []

      if (pageDivs.length > 0) {
        pageDivs.forEach((page, index) => {
          const pageText = this.cleanText(page.textContent)
          if (pageText && pageText.length >= 2) {
            results.push({
              page: index + 1,
              text: pageText,
              type: 'doc-page',
              element: page
            })
          }
        })
      } else {
        const fullText = this.cleanText(viewer.textContent)
        if (fullText) {
          results.push({
            page: 1,
            text: fullText,
            type: 'doc-full',
            element: viewer
          })
        }
      }

      console.log(`✅ TextExtractor: DOC extraction complete, found ${results.length} pages`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: DOC extraction failed', error)
      return this.extractDomText(container)
    }
  }

  async extractExcelText(container) {
    console.log('📄 TextExtractor: starting Excel/CSV text extraction')

    try {
      const tables = container.querySelectorAll('table')
      const results = []

      if (tables.length === 0) {
        console.warn('⚠️ TextExtractor: no tables found in Excel/CSV content')
        return this.extractDomText(container)
      }

      tables.forEach((table, tableIndex) => {
        const rows = table.querySelectorAll('tr')
        
        rows.forEach((row, rowIndex) => {
          const cells = row.querySelectorAll('td, th')
          
          cells.forEach((cell, colIndex) => {
            const cellText = this.cleanText(cell.textContent)
            
            if (cellText && cellText.length >= 1) {
              results.push({
                location: {
                  table: tableIndex + 1,
                  row: rowIndex + 1,
                  col: colIndex + 1
                },
                text: cellText,
                type: cell.tagName.toLowerCase() === 'th' ? 'header-cell' : 'data-cell',
                element: cell
              })
            }
          })
        })
      })

      console.log(`✅ TextExtractor: Excel/CSV extraction complete, found ${results.length} cells across ${tables.length} table(s)`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: Excel/CSV extraction failed', error)
      return this.extractDomText(container)
    }
  }

  async extractPptxText(container) {
    console.log('📄 TextExtractor: starting PPTX text extraction')

    try {
      const slideContainerSelectors = [
        '.slide-container',
        '[data-slide-index]',
        '.pptx-slide',
        '.presentation-slides',
        '.slides-container'
      ]

      let slideContainer = null
      for (const selector of slideContainerSelectors) {
        slideContainer = container.querySelector(selector)
        if (slideContainer) break
      }

      const results = []

      if (slideContainer) {
        const slideSelectors = [
          '.slide',
          '[data-slide-index]',
          '.pptx-slide',
          '.presentation-slide'
        ]

        let slides = []
        for (const selector of slideSelectors) {
          slides = slideContainer.querySelectorAll(selector)
          if (slides.length > 0) break
        }

        if (slides.length > 0) {
          slides.forEach((slide, index) => {
            const slideText = this.cleanText(slide.textContent)
            if (slideText && slideText.length >= 2) {
              results.push({
                page: index + 1,
                text: slideText,
                type: 'pptx-slide',
                location: { slide: index + 1 },
                element: slide
              })
            }
          })
        } else {
          const containerText = this.cleanText(slideContainer.textContent)
          if (containerText) {
            results.push({
              page: 1,
              text: containerText,
              type: 'pptx-container',
              element: slideContainer
            })
          }
        }
      } else {
        console.log('⚠️ TextExtractor: PPTX slide container not found, trying fallback strategies')

        const styledDivs = Array.from(container.querySelectorAll('div')).filter(div => {
          const style = window.getComputedStyle(div)
          const width = parseFloat(style.width)
          const height = parseFloat(style.height)
          return width > 400 && height > 300
        })

        if (styledDivs.length > 0) {
          styledDivs.forEach((div, index) => {
            const divText = this.cleanText(div.textContent)
            if (divText && divText.length >= 2) {
              results.push({
                page: index + 1,
                text: divText,
                type: 'pptx-fallback-div',
                location: { slide: index + 1 },
                element: div
              })
            }
          })
        } else {
          console.log('⚠️ TextExtractor: using final PPTX fallback - entire container as one slide')
          const containerText = this.cleanText(container.textContent)
          if (containerText) {
            results.push({
              page: 1,
              text: containerText,
              type: 'pptx-final-fallback',
              element: container
            })
          }
        }
      }

      console.log(`✅ TextExtractor: PPTX extraction complete, found ${results.length} slides`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: PPTX extraction failed', error)
      return this.extractDomText(container)
    }
  }

  extractDomText(container) {
    console.log('📄 TextExtractor: starting DOM text extraction using TreeWalker')

    try {
      const excludedTags = new Set(['SCRIPT', 'STYLE', 'CODE', 'PRE', 'NOSCRIPT', 'TEMPLATE'])
      const excludeClasses = new Set(['search-highlight', 'ref-highlight'])
      const results = []

      const walker = document.createTreeWalker(
        container,
        NodeFilter.SHOW_TEXT,
        {
          acceptNode: (node) => {
            const parent = node.parentElement
            
            if (!parent) {
              return NodeFilter.FILTER_REJECT
            }

            if (excludedTags.has(parent.tagName)) {
              return NodeFilter.FILTER_REJECT
            }

            const style = window.getComputedStyle(parent)
            if (style.display === 'none' || style.visibility === 'hidden') {
              return NodeFilter.FILTER_REJECT
            }

            if (parent.classList) {
              for (const className of parent.classList) {
                if (excludeClasses.has(className)) {
                  return NodeFilter.FILTER_REJECT
                }
              }
            }

            if (parent.tagName === 'MARK' || parent.closest('.search-highlight, .ref-highlight')) {
              return NodeFilter.FILTER_REJECT
            }

            const text = node.textContent.trim()
            if (!text || text.length < 2) {
              return NodeFilter.FILTER_REJECT
            }

            return NodeFilter.FILTER_ACCEPT
          }
        }
      )

      let node
      while ((node = walker.nextNode())) {
        const text = this.cleanText(node.textContent)
        if (text && text.length >= 2) {
          results.push({
            text: text,
            type: 'dom-text',
            element: node.parentElement
          })
        }
      }

      if (results.length === 0) {
        console.log('⚠️ TextExtractor: TreeWalker yielded no results, using textContent fallback')
        const fallbackText = this.cleanText(container.textContent)
        if (fallbackText && fallbackText.length >= 2) {
          results.push({
            text: fallbackText,
            type: 'dom-fallback',
            element: container
          })
        }
      }

      console.log(`✅ TextExtractor: DOM extraction complete, found ${results.length} text nodes`)
      return results

    } catch (error) {
      console.error('❌ TextExtractor: DOM extraction failed', error)
      console.log('⚠️ TextExtractor: using direct textContent fallback')
      
      try {
        const text = this.cleanText(container.textContent)
        if (!text || text.length < 2) {
          return []
        }
        return [{ text, type: 'dom-error-fallback', element: container }]
      } catch (fallbackError) {
        console.error('❌ TextExtractor: fallback also failed', fallbackError)
        return []
      }
    }
  }

  async extractPlainText(container) {
    console.log('📄 TextExtractor: extracting plain text')

    try {
      const text = this.cleanText(container.textContent)
      
      if (!text || text.length < 2) {
        console.log('⚠️ TextExtractor: no meaningful text content found')
        return []
      }

      console.log(`✅ TextExtractor: plain text extraction complete, ${text.length} characters`)
      return [{ text, type: 'plain-text', element: container }]

    } catch (error) {
      console.error('❌ TextExtractor: plain text extraction failed', error)
      return []
    }
  }

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

    return text
      .replace(/[\r\n\t]+/g, ' ')
      .replace(/\s{2,}/g, ' ')
      .trim()
  }

  isSupported(fileType) {
    return this.supportedTypes.includes(fileType?.toLowerCase())
  }

  getSupportedTypes() {
    return [...this.supportedTypes]
  }
}

export default new TextExtractor()
