<template>
  <div class="app" :class="{ 'reading-mode': isReading }">
    <div class="grid-container" v-if="!isReading">
      <header class="masthead">
        <div class="header-top">
          <h1 class="title">Slow Reader</h1>
          <button @click="toggleDarkMode" class="theme-toggle" :title="isDarkMode ? 'Switch to light mode' : 'Switch to dark mode'">
            {{ isDarkMode ? '☀' : '🌙' }}
          </button>
        </div>
      </header>

      <section class="input-section">
        <div class="input-tabs">
          <button 
            @click="inputMode = 'text'" 
            class="input-tab"
            :class="{ active: inputMode === 'text' }"
          >
            Paste Text
          </button>
          <button 
            @click="inputMode = 'pdf'" 
            class="input-tab"
            :class="{ active: inputMode === 'pdf' }"
          >
            Upload PDF
          </button>
          <button 
            @click="inputMode = 'url'" 
            class="input-tab"
            :class="{ active: inputMode === 'url' }"
          >
            Article URL
          </button>
        </div>

        <div class="input-group" v-if="inputMode === 'text'">
          <textarea
            v-model="inputText"
            class="text-input"
            placeholder="Paste your article, essay, or any text you'd like to read with intention..."
            rows="8"
          ></textarea>
        </div>

        <div class="input-group" v-if="inputMode === 'pdf'">
          <div 
            class="pdf-upload-area"
            :class="{ 
              'drag-over': isDragOver,
              'processing': isProcessingPDF,
              'has-file': uploadedFileName
            }"
            @drop="handleDrop"
            @dragover.prevent="isDragOver = true"
            @dragleave="isDragOver = false"
            @click="triggerFileInput"
          >
            <input
              type="file"
              ref="fileInput"
              accept=".pdf"
              @change="handleFileSelect"
              style="display: none"
            >
            
            <div class="upload-content" v-if="!isProcessingPDF && !uploadedFileName">
              <div class="upload-icon">📄</div>
              <p class="upload-text">Drop your PDF here or click to upload</p>
              <p class="upload-hint">Simple text PDFs work best</p>
            </div>
            
            <div class="processing-content" v-if="isProcessingPDF">
              <div class="processing-spinner"></div>
              <p class="processing-text">Extracting text from PDF...</p>
              <div class="processing-progress" v-if="processingProgress > 0">
                {{ processingProgress }}% complete
              </div>
            </div>
            
            <div class="file-info" v-if="uploadedFileName && !isProcessingPDF">
              <div class="file-icon">✓</div>
              <p class="file-name">{{ uploadedFileName }}</p>
              <p class="file-status">{{ extractedWords }} words extracted</p>
              <button @click.stop="clearFile" class="clear-file">×</button>
            </div>
          </div>
          
          <div class="pdf-error" v-if="pdfError">
            <p>{{ pdfError }}</p>
            <button @click="pdfError = null" class="dismiss-error">Dismiss</button>
          </div>
        </div>

        <div class="input-group" v-if="inputMode === 'url'">
          <div class="url-input-area">
            <input
              type="url"
              v-model="articleUrl"
              class="url-input"
              placeholder="https://www.nytimes.com/article-url..."
              :disabled="isExtractingArticle"
            >
            <button 
              @click="extractArticle" 
              class="extract-button"
              :disabled="!articleUrl.trim() || isExtractingArticle"
            >
              {{ isExtractingArticle ? 'Extracting...' : 'Extract Article' }}
            </button>
          </div>
          
          <div class="extraction-progress" v-if="isExtractingArticle">
            <div class="processing-spinner"></div>
            <p class="processing-text">Extracting article content...</p>
          </div>
          
          <div class="article-info" v-if="extractedArticle && !isExtractingArticle">
            <div class="article-icon">📰</div>
            <div class="article-details">
              <h3 class="article-title">{{ extractedArticle.title }}</h3>
              <p class="article-stats">{{ extractedArticle.word_count }} words extracted</p>
              <button @click="clearArticle" class="clear-article">×</button>
            </div>
          </div>
          
          <div class="url-error" v-if="urlError">
            <p>{{ urlError }}</p>
            <button @click="urlError = null" class="dismiss-error">Dismiss</button>
          </div>
        </div>
        
        <!-- Text analysis hidden for now -->
        <div class="text-analysis" v-if="false && textDifficulty">
          <div class="analysis-item">
            <span class="analysis-label">Text Difficulty:</span>
            <span class="analysis-value">{{ textDifficulty.difficulty_level }}</span>
          </div>
          <div class="analysis-item">
            <span class="analysis-label">Suggested Speed:</span>
            <span class="analysis-value suggested-wpm" @click="usesSuggestedSpeed = true; baseSpeed = textDifficulty.suggested_wpm">
              {{ textDifficulty.suggested_wpm }} WPM
            </span>
          </div>
          <div class="analysis-item">
            <span class="analysis-label">Estimated Time:</span>
            <span class="analysis-value">{{ textDifficulty.reading_time_minutes }} min</span>
          </div>
        </div>

        <div class="settings-bar">
          <div class="speed-setting">
            <label class="setting-label">Reading Speed</label>
            <div class="speed-selector">
              <input 
                type="range" 
                v-model.number="baseSpeed" 
                min="100" 
                max="300" 
                step="10"
                class="speed-slider"
              >
              <span class="speed-display">{{ baseSpeed }} WPM</span>
            </div>
          </div>
          
          <button 
            @click="startReading" 
            class="start-button"
            :disabled="!inputText.trim()"
          >
            Begin Reading
          </button>
        </div>
      </section>
    </div>

    <div class="reading-mode-container" v-if="isReading">
      <div class="reading-content">
        <div class="reading-text" ref="readingText">
          <span 
            v-for="(word, index) in revealedWords" 
            :key="index"
            class="word"
            :class="{
              'current': index === currentWordIndex,
              'past': index < currentWordIndex
            }"
            :style="getWordFadeStyle(index)"
          >
            {{ word }}{{ ' ' }}
          </span>
        </div>
      </div>
      
      <div class="reading-controls">
        <button @click="togglePause" class="control-btn">
          {{ isPaused ? '▶' : '⏸' }}
        </button>
        <button @click="stopReading" class="control-btn">
          ×
        </button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      inputText: `These days we may find ourselves skimming articles, jumping between paragraphs and looking for key points. Maybe it's just how we read now—always rushing, always extracting. But there's something worth considering about what gets lost when we're constantly racing through text.

When you can't speed through something, reading changes. You start noticing how sentences actually flow together, how ideas build on each other instead of just existing as isolated points. Words you'd normally gloss over suddenly mean something. It's like the difference between scanning a room for your keys and actually noticing what's in it.

Most of us treat reading like data mining—get in, find what we need, get out. But when you slow down, it becomes something else entirely. Less like a task, more like a conversation with the text.

When you give text more time, you just understand it better. You catch connections you'd miss otherwise. You actually remember what you read instead of forgetting it five minutes later.

That's what Slow Reader is about. Just you and the text, moving at a pace that lets you actually think.`,
      baseSpeed: 200,
      isReading: false,
      isPaused: false,
      words: [],
      revealedWords: [],
      currentWordIndex: -1,
      totalWords: 0,
      progressPercent: 0,
      effectiveSpeed: 200,
      elapsedTime: 0,
      websocket: null,
      startTime: null,
      spacePressedTime: null,
      isSpacePressed: false,
      isDarkMode: false,
      inputMode: 'text',
      isDragOver: false,
      isProcessingPDF: false,
      processingProgress: 0,
      uploadedFileName: null,
      extractedWords: 0,
      pdfError: null,
      articleUrl: '',
      isExtractingArticle: false,
      extractedArticle: null,
      urlError: null,
      textDifficulty: null,
      usesSuggestedSpeed: false
    }
  },
  watch: {
    // Text analysis disabled for now
    // inputText: {
    //   handler: 'analyzeTextDifficulty',
    //   immediate: true
    // }
  },
  mounted() {
    document.addEventListener('keydown', this.handleKeyDown)
    document.addEventListener('keyup', this.handleKeyUp)
    
    // Load dark mode preference
    const savedDarkMode = localStorage.getItem('darkMode')
    if (savedDarkMode !== null) {
      this.isDarkMode = JSON.parse(savedDarkMode)
    } else {
      // Default to system preference
      this.isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
    }
    
    this.updateTheme()
  },
  beforeUnmount() {
    document.removeEventListener('keydown', this.handleKeyDown)
    document.removeEventListener('keyup', this.handleKeyUp)
    document.body.classList.remove('reading-mode')
    if (this.websocket) {
      this.websocket.close()
    }
  },
  methods: {
    async startReading() {
      if (!this.inputText.trim()) return
      
      this.words = this.inputText.trim().split(/\s+/)
      this.revealedWords = []
      this.totalWords = this.words.length
      this.currentWordIndex = -1
      this.isReading = true
      this.startTime = Date.now()
      
      // Add reading mode class to body
      document.body.classList.add('reading-mode')
      
      // Connect to WebSocket
      this.connectWebSocket()
    },
    
    connectWebSocket() {
      const wsUrl = `ws://localhost:8000/ws/reading-session`
      this.websocket = new WebSocket(wsUrl)
      
      this.websocket.onopen = () => {
        // Start reading session
        this.websocket.send(JSON.stringify({
          type: 'start_reading',
          text: this.inputText,
          base_speed: this.baseSpeed
        }))
      }
      
      this.websocket.onmessage = (event) => {
        const data = JSON.parse(event.data)
        
        if (data.type === 'analysis_complete') {
          this.effectiveSpeed = data.analysis.final_wpm
          this.totalWords = data.total_words
        } else if (data.type === 'word_reveal') {
          this.currentWordIndex = data.word_index
          this.revealedWords = data.revealed_words
          this.progressPercent = data.progress * 100
          this.updateElapsedTime()
        } else if (data.type === 'session_complete') {
          this.stopReading()
        }
      }
      
      this.websocket.onerror = (error) => {
        console.error('WebSocket error:', error)
        alert('Could not connect to server. Please make sure the backend is running.')
      }
    },
    
    togglePause() {
      this.isPaused = !this.isPaused
      
      if (this.websocket) {
        this.websocket.send(JSON.stringify({
          type: this.isPaused ? 'pause' : 'resume'
        }))
      }
    },
    
    stopReading() {
      this.isReading = false
      this.isPaused = false
      this.currentWordIndex = -1
      this.revealedWords = []
      this.progressPercent = 0
      this.elapsedTime = 0
      
      // Remove reading mode class from body
      document.body.classList.remove('reading-mode')
      
      if (this.websocket) {
        this.websocket.send(JSON.stringify({
          type: 'stop'
        }))
        this.websocket.close()
        this.websocket = null
      }
    },
    
    handleKeyDown(event) {
      if (!this.isReading) return
      
      if (event.code === 'Space' && !this.isSpacePressed) {
        event.preventDefault()
        this.isSpacePressed = true
        this.spacePressedTime = Date.now()
        
        if (!this.isPaused) {
          this.togglePause()
        }
      } else if (event.code === 'Escape') {
        event.preventDefault()
        this.stopReading()
      }
    },
    
    handleKeyUp(event) {
      if (!this.isReading) return
      
      if (event.code === 'Space' && this.isSpacePressed) {
        event.preventDefault()
        this.isSpacePressed = false
        
        if (this.isPaused) {
          this.togglePause()
        }
      }
    },
    
    updateElapsedTime() {
      if (this.startTime) {
        this.elapsedTime = Math.floor((Date.now() - this.startTime) / 1000)
      }
    },
    
    formatTime(seconds) {
      const mins = Math.floor(seconds / 60)
      const secs = seconds % 60
      return `${mins}:${secs.toString().padStart(2, '0')}`
    },
    
    toggleDarkMode() {
      this.isDarkMode = !this.isDarkMode
      localStorage.setItem('darkMode', JSON.stringify(this.isDarkMode))
      this.updateTheme()
    },
    
    updateTheme() {
      if (this.isDarkMode) {
        document.body.classList.add('dark-mode')
      } else {
        document.body.classList.remove('dark-mode')
      }
    },
    
    triggerFileInput() {
      this.$refs.fileInput.click()
    },
    
    handleFileSelect(event) {
      const file = event.target.files[0]
      if (file) {
        this.processPDF(file)
      }
    },
    
    handleDrop(event) {
      event.preventDefault()
      this.isDragOver = false
      
      const files = Array.from(event.dataTransfer.files)
      const pdfFile = files.find(file => file.type === 'application/pdf')
      
      if (pdfFile) {
        this.processPDF(pdfFile)
      } else {
        this.pdfError = 'Please upload a valid PDF file.'
      }
    },
    
    async processPDF(file) {
      this.isProcessingPDF = true
      this.processingProgress = 0
      this.pdfError = null
      this.uploadedFileName = file.name
      
      try {
        // Dynamic import to reduce initial bundle size
        const pdfjsLib = await import('pdfjs-dist')
        
        // Set worker path - use local worker file for development
        pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js'
        
        const arrayBuffer = await file.arrayBuffer()
        const pdf = await pdfjsLib.getDocument(arrayBuffer).promise
        
        let fullText = ''
        const totalPages = pdf.numPages
        
        for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
          this.processingProgress = Math.round((pageNum / totalPages) * 100)
          
          const page = await pdf.getPage(pageNum)
          const textContent = await page.getTextContent()
          
          // Extract text items and preserve some structure
          const textItems = textContent.items
          let pageText = ''
          
          for (let i = 0; i < textItems.length; i++) {
            const item = textItems[i]
            const nextItem = textItems[i + 1]
            
            pageText += item.str
            
            // Add space if needed between text items
            if (nextItem) {
              const currentY = item.transform[5]
              const nextY = nextItem.transform[5]
              const currentX = item.transform[4] + item.width
              const nextX = nextItem.transform[4]
              
              // New line if Y position changed significantly
              if (Math.abs(currentY - nextY) > 5) {
                pageText += '\n'
              }
              // Space if there's a gap between text items on same line
              else if (nextX - currentX > 5) {
                pageText += ' '
              }
            }
          }
          
          fullText += pageText + '\n\n'
        }
        
        // Clean and format the extracted text
        const cleanedText = this.cleanExtractedText(fullText)
        
        if (cleanedText.trim().length === 0) {
          throw new Error('No readable text found in PDF. This might be a scanned document or image-based PDF.')
        }
        
        this.inputText = cleanedText
        this.extractedWords = cleanedText.split(/\s+/).filter(word => word.length > 0).length
        
        // Switch to text mode to show the result
        setTimeout(() => {
          this.inputMode = 'text'
        }, 1000)
        
      } catch (error) {
        console.error('PDF processing error:', error)
        this.pdfError = error.message || 'Failed to extract text from PDF. Please try a different file.'
        this.uploadedFileName = null
      } finally {
        this.isProcessingPDF = false
        this.processingProgress = 0
      }
    },
    
    cleanExtractedText(text) {
      return text
        // Remove excessive whitespace
        .replace(/\s+/g, ' ')
        // Remove excessive line breaks
        .replace(/\n\s*\n\s*\n/g, '\n\n')
        // Fix common PDF extraction issues
        .replace(/([a-z])([A-Z])/g, '$1 $2') // Add space between lowercase and uppercase
        .replace(/(\w)-\s*\n\s*(\w)/g, '$1$2') // Fix hyphenated words split across lines
        // Clean up
        .trim()
    },
    
    clearFile() {
      this.uploadedFileName = null
      this.extractedWords = 0
      this.inputText = ''
      this.pdfError = null
      if (this.$refs.fileInput) {
        this.$refs.fileInput.value = ''
      }
    },
    
    async extractArticle() {
      if (!this.articleUrl.trim()) return
      
      this.isExtractingArticle = true
      this.urlError = null
      this.extractedArticle = null
      
      try {
        const response = await fetch('/api/extract-article', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            url: this.articleUrl.trim()
          })
        })
        
        if (!response.ok) {
          const errorData = await response.json()
          throw new Error(errorData.detail || 'Failed to extract article')
        }
        
        const data = await response.json()
        
        this.extractedArticle = {
          title: data.title,
          word_count: data.word_count,
          extraction_method: data.extraction_method
        }
        
        this.inputText = data.text
        
        // Switch to text mode to show the result
        setTimeout(() => {
          this.inputMode = 'text'
        }, 1500)
        
      } catch (error) {
        console.error('Article extraction error:', error)
        this.urlError = error.message || 'Failed to extract article. Please check the URL and try again.'
      } finally {
        this.isExtractingArticle = false
      }
    },
    
    clearArticle() {
      this.extractedArticle = null
      this.articleUrl = ''
      this.inputText = ''
      this.urlError = null
    },
    
    getWordFadeStyle(index) {
      if (index === this.currentWordIndex) {
        // Current word - fully visible
        return { opacity: 1 }
      } else if (index < this.currentWordIndex) {
        // Past words - fade based on distance from current word
        const wordsBehind = this.currentWordIndex - index
        const maxFadeDistance = 20 // Fade over 20 words
        
        if (wordsBehind > maxFadeDistance) {
          return { opacity: 0.1 }
        }
        
        // Linear fade from 1.0 to 0.1
        const fadeAmount = 1 - (wordsBehind / maxFadeDistance) * 0.9
        return { 
          opacity: Math.max(0.1, fadeAmount),
          transition: 'opacity 1s ease-out'
        }
      }
      
      // Future words - not visible yet
      return { opacity: 1 }
    },
    
    async analyzeTextDifficulty() {
      if (!this.inputText.trim() || this.inputText.trim().length < 50) {
        this.textDifficulty = null
        return
      }
      
      try {
        const response = await fetch('/api/analyze-text', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            text: this.inputText.trim(),
            base_speed: this.baseSpeed
          })
        })
        
        if (response.ok) {
          const data = await response.json()
          this.textDifficulty = data.analysis.text_difficulty
          
          // Auto-apply suggested speed if user hasn't manually changed it
          if (!this.usesSuggestedSpeed && data.analysis.text_difficulty.suggested_wpm !== this.baseSpeed) {
            // Only auto-apply if the difference is significant (more than 20 WPM)
            const difference = Math.abs(data.analysis.text_difficulty.suggested_wpm - this.baseSpeed)
            if (difference > 20) {
              this.baseSpeed = data.analysis.text_difficulty.suggested_wpm
            }
          }
        }
      } catch (error) {
        console.error('Text analysis failed:', error)
        this.textDifficulty = null
      }
    }
  }
}
</script>