import { Controller } from "@hotwired/stimulus"
import {
  loadJson,
  saveJson,
  MATCH_DATA_TTL_MS
} from "match-state-transport"

export default class extends Controller {
  static targets = [
    "w1Stat", "w2Stat", "statusIndicator"
  ]

  static values = {
    tournamentId: Number,
    boutNumber: Number,
    matchId: Number
  }

  connect() {
    console.log("Match data controller connected")
    this.isConnected = false
    this.pendingLocalSync = { w1: false, w2: false }
    
    this.w1 = {
      name: "w1",
      stats: "",
      updated_at: null,
      timers: {
        "injury": { time: 0, startTime: null, interval: null },
        "blood": { time: 0, startTime: null, interval: null }
      }
    }
    
    this.w2 = {
      name: "w2",
      stats: "", 
      updated_at: null,
      timers: {
        "injury": { time: 0, startTime: null, interval: null },
        "blood": { time: 0, startTime: null, interval: null }
      }
    }
    
    // Initial values
    this.updateJsValues()
    
    // Set up debounced handlers for text areas
    this.debouncedW1Handler = this.debounce((el) => this.handleTextAreaInput(el, this.w1), 400)
    this.debouncedW2Handler = this.debounce((el) => this.handleTextAreaInput(el, this.w2), 400)
    
    // Set up text area event listeners
    this.w1StatTarget.addEventListener('input', (event) => this.debouncedW1Handler(event.target))
    this.w2StatTarget.addEventListener('input', (event) => this.debouncedW2Handler(event.target))
    
    // Initialize from local storage
    this.initializeFromLocalStorage()
    
    // Setup ActionCable
    if (this.matchIdValue) {
      this.setupSubscription(this.matchIdValue)
    }
  }
  
  disconnect() {
    this.cleanupSubscription()
  }
  
  // Match stats core functionality
  updateStats(wrestler, text) {
    if (!wrestler) { 
      console.error("updateStats called with undefined wrestler")
      return
    }
    
    wrestler.stats += text + " "
    wrestler.updated_at = new Date().toISOString()
    this.updateHtmlValues()
    this.saveToLocalStorage(wrestler)
    if (!this.isConnected) this.pendingLocalSync[wrestler.name] = true
    
    // Send the update via Action Cable if subscribed
    if (this.matchSubscription) {
      let payload = {}
      if (wrestler.name === 'w1') payload.new_w1_stat = wrestler.stats
      else if (wrestler.name === 'w2') payload.new_w2_stat = wrestler.stats
      
      if (Object.keys(payload).length > 0) {
        console.log('[ActionCable] updateStats performing send_stat:', payload)
        this.matchSubscription.perform('send_stat', payload)
      }
    } else {
      console.warn('[ActionCable] updateStats called but matchSubscription is null.')
    }
  }
  
  // Specific methods for updating each wrestler
  updateW1Stats(event) {
    const text = event.currentTarget.dataset.matchDataText || ''
    this.updateStats(this.w1, text)
  }

  updateW2Stats(event) {
    const text = event.currentTarget.dataset.matchDataText || ''
    this.updateStats(this.w2, text)
  }

  // End period action
  endPeriod() {
    this.updateStats(this.w1, '|End Period|')
    this.updateStats(this.w2, '|End Period|')
  }
  
  handleTextAreaInput(textAreaElement, wrestler) {
    const newValue = textAreaElement.value
    console.log(`Text area input detected for ${wrestler.name}:`, newValue.substring(0, 50) + "...")
    
    // Update the internal JS object
    wrestler.stats = newValue
    wrestler.updated_at = new Date().toISOString()
    if (!this.isConnected) this.pendingLocalSync[wrestler.name] = true
    
    // Save to localStorage
    this.saveToLocalStorage(wrestler)
    
    // Send the update via Action Cable if subscribed
    if (this.matchSubscription) {
      let payload = {}
      if (wrestler.name === 'w1') {
        payload.new_w1_stat = wrestler.stats
      } else if (wrestler.name === 'w2') {
        payload.new_w2_stat = wrestler.stats
      }
      if (Object.keys(payload).length > 0) {
        console.log('[ActionCable] Performing send_stat from textarea with payload:', payload)
        this.matchSubscription.perform('send_stat', payload)
      }
    }
  }
  
  // Timer functions
  startTimer(wrestler, timerKey) {
    const timer = wrestler.timers[timerKey]
    if (timer.interval) return // Prevent multiple intervals
    
    timer.startTime = Date.now()
    timer.interval = setInterval(() => {
      const elapsedSeconds = Math.floor((Date.now() - timer.startTime) / 1000)
      this.updateTimerDisplay(wrestler, timerKey, timer.time + elapsedSeconds)
    }, 1000)
  }
  
  stopTimer(wrestler, timerKey) {
    const timer = wrestler.timers[timerKey]
    if (!timer.interval || !timer.startTime) return
    
    clearInterval(timer.interval)
    const elapsedSeconds = Math.floor((Date.now() - timer.startTime) / 1000)
    timer.time += elapsedSeconds
    timer.interval = null
    timer.startTime = null
    
    this.saveToLocalStorage(wrestler)
    this.updateTimerDisplay(wrestler, timerKey, timer.time)
    this.updateStatsBox(wrestler, timerKey, elapsedSeconds)
  }
  
  resetTimer(wrestler, timerKey) {
    const timer = wrestler.timers[timerKey]
    this.stopTimer(wrestler, timerKey)
    timer.time = 0
    this.updateTimerDisplay(wrestler, timerKey, 0)
    this.saveToLocalStorage(wrestler)
  }
  
  // Timer control methods for W1
  startW1InjuryTimer() {
    this.startTimer(this.w1, 'injury')
  }

  stopW1InjuryTimer() {
    this.stopTimer(this.w1, 'injury')
  }

  resetW1InjuryTimer() {
    this.resetTimer(this.w1, 'injury')
  }

  startW1BloodTimer() {
    this.startTimer(this.w1, 'blood')
  }

  stopW1BloodTimer() {
    this.stopTimer(this.w1, 'blood')
  }

  resetW1BloodTimer() {
    this.resetTimer(this.w1, 'blood')
  }

  // Timer control methods for W2
  startW2InjuryTimer() {
    this.startTimer(this.w2, 'injury')
  }

  stopW2InjuryTimer() {
    this.stopTimer(this.w2, 'injury')
  }

  resetW2InjuryTimer() {
    this.resetTimer(this.w2, 'injury')
  }

  startW2BloodTimer() {
    this.startTimer(this.w2, 'blood')
  }

  stopW2BloodTimer() {
    this.stopTimer(this.w2, 'blood')
  }

  resetW2BloodTimer() {
    this.resetTimer(this.w2, 'blood')
  }
  
  updateTimerDisplay(wrestler, timerKey, totalTime) {
    const elementId = `${wrestler.name}-${timerKey}-time`
    const element = document.getElementById(elementId)
    if (element) {
      element.innerText = `${Math.floor(totalTime / 60)}m ${totalTime % 60}s`
    }
  }
  
  updateStatsBox(wrestler, timerKey, elapsedSeconds) {
    const timerType = timerKey.includes("injury") ? "Injury Time" : "Blood Time"
    const formattedTime = `${Math.floor(elapsedSeconds / 60)}m ${elapsedSeconds % 60}s`
    this.updateStats(wrestler, `${timerType}: ${formattedTime}`)
  }
  
  // Utility functions
  generateKey(wrestler_name) {
    return `${wrestler_name}-${this.tournamentIdValue}-${this.boutNumberValue}`
  }
  
  loadFromLocalStorage(wrestler_name) {
    const key = this.generateKey(wrestler_name)
    return loadJson(localStorage, key)
  }
  
  saveToLocalStorage(person) {
    const key = this.generateKey(person.name)
    const data = {
      stats: person.stats,
      updated_at: person.updated_at,
      timers: person.timers
    }
    saveJson(localStorage, key, data, { ttlMs: MATCH_DATA_TTL_MS })
  }
  
  updateHtmlValues() {
    if (this.w1StatTarget) this.w1StatTarget.value = this.w1.stats
    if (this.w2StatTarget) this.w2StatTarget.value = this.w2.stats
  }
  
  updateJsValues() {
    if (this.w1StatTarget) this.w1.stats = this.w1StatTarget.value
    if (this.w2StatTarget) this.w2.stats = this.w2StatTarget.value
  }
  
  debounce(func, wait) {
    let timeout
    return (...args) => {
      clearTimeout(timeout)
      timeout = setTimeout(() => func(...args), wait)
    }
  }
  
  initializeTimers(wrestler) {
    for (const timerKey in wrestler.timers) {
      this.updateTimerDisplay(wrestler, timerKey, wrestler.timers[timerKey].time)
    }
  }
  
  initializeFromLocalStorage() {
    const w1Data = this.loadFromLocalStorage('w1')
    if (w1Data) {
      this.w1.stats = w1Data.stats || ''
      this.w1.updated_at = w1Data.updated_at
      if (w1Data.timers) this.w1.timers = w1Data.timers
      this.initializeTimers(this.w1)
    }
    
    const w2Data = this.loadFromLocalStorage('w2')
    if (w2Data) {
      this.w2.stats = w2Data.stats || ''
      this.w2.updated_at = w2Data.updated_at
      if (w2Data.timers) this.w2.timers = w2Data.timers
      this.initializeTimers(this.w2)
    }
    
    this.updateHtmlValues()
  }
  
  cleanupSubscription() {
    if (this.matchSubscription) {
      console.log(`[Stats AC Cleanup] Unsubscribing from match channel.`)
      try {
        this.matchSubscription.unsubscribe()
      } catch (e) {
        console.error(`[Stats AC Cleanup] Error during unsubscribe:`, e)
      }
      this.matchSubscription = null
    }
  }
  
  setupSubscription(matchId) {
    this.cleanupSubscription()
    console.log(`[Stats AC Setup] Attempting subscription for match ID: ${matchId}`)
    
    // Update status indicator
    if (this.statusIndicatorTarget) {
      this.statusIndicatorTarget.innerText = "Connecting to server for real-time stat updates..."
      this.statusIndicatorTarget.classList.remove('alert-success', 'alert-warning', 'alert-danger')
      this.statusIndicatorTarget.classList.add('alert-info')
    }
    
    // Exit if we don't have App.cable
    if (!window.App || !window.App.cable) {
      console.error(`[Stats AC Setup] Error: App.cable is not available.`)
      if (this.statusIndicatorTarget) {
        this.statusIndicatorTarget.innerText = "Error: WebSockets unavailable. Stats won't update in real-time."
        this.statusIndicatorTarget.classList.remove('alert-info', 'alert-success', 'alert-warning')
        this.statusIndicatorTarget.classList.add('alert-danger')
      }
      return
    }
    
    this.matchSubscription = App.cable.subscriptions.create(
      {
        channel: "MatchChannel",
        match_id: matchId
      },
      {
        connected: () => {
          console.log(`[Stats AC] Connected to MatchStatsChannel for match ID: ${matchId}`)
          this.isConnected = true
          if (this.statusIndicatorTarget) {
            this.statusIndicatorTarget.innerText = "Connected: Stats will update in real-time."
            this.statusIndicatorTarget.classList.remove('alert-info', 'alert-warning', 'alert-danger')
            this.statusIndicatorTarget.classList.add('alert-success')
          }
          this.sendCurrentStatsOnReconnect()
        },
        
        disconnected: () => {
          console.log(`[Stats AC] Disconnected from MatchStatsChannel`)
          this.isConnected = false
          if (this.statusIndicatorTarget) {
            this.statusIndicatorTarget.innerText = "Disconnected: Stats updates paused."
            this.statusIndicatorTarget.classList.remove('alert-info', 'alert-success', 'alert-danger')
            this.statusIndicatorTarget.classList.add('alert-warning')
          }
        },
        
        received: (data) => {
          console.log(`[Stats AC] Received data:`, data)
          
          // Update w1 stats
          if (data.w1_stat !== undefined && this.w1StatTarget) {
            console.log(`[Stats AC] Updating w1_stat: ${data.w1_stat.substring(0, 30)}...`)
            if (!this.pendingLocalSync.w1 || data.w1_stat === this.w1.stats) {
              this.w1.stats = data.w1_stat
              this.w1StatTarget.value = data.w1_stat
              this.pendingLocalSync.w1 = false
            } else {
              console.log('[Stats AC] Skipping w1_stat overwrite due to pending local changes.')
            }
          }
          
          // Update w2 stats
          if (data.w2_stat !== undefined && this.w2StatTarget) {
            console.log(`[Stats AC] Updating w2_stat: ${data.w2_stat.substring(0, 30)}...`)
            if (!this.pendingLocalSync.w2 || data.w2_stat === this.w2.stats) {
              this.w2.stats = data.w2_stat
              this.w2StatTarget.value = data.w2_stat
              this.pendingLocalSync.w2 = false
            } else {
              console.log('[Stats AC] Skipping w2_stat overwrite due to pending local changes.')
            }
          }
        },
        
        receive_error: (error) => {
          console.error(`[Stats AC] Error:`, error)
          this.matchSubscription = null
          
          if (this.statusIndicatorTarget) {
            this.statusIndicatorTarget.innerText = "Error: Connection issue. Stats won't update in real-time."
            this.statusIndicatorTarget.classList.remove('alert-info', 'alert-success', 'alert-warning')
            this.statusIndicatorTarget.classList.add('alert-danger')
          }
        }
      }
    )
  }

  sendCurrentStatsOnReconnect() {
    if (!this.matchSubscription) return
    const payload = {}
    if (typeof this.w1?.stats === 'string' && this.w1.stats.length > 0) {
      payload.new_w1_stat = this.w1.stats
      this.pendingLocalSync.w1 = true
    }
    if (typeof this.w2?.stats === 'string' && this.w2.stats.length > 0) {
      payload.new_w2_stat = this.w2.stats
      this.pendingLocalSync.w2 = true
    }
    if (Object.keys(payload).length > 0) {
      console.log('[ActionCable] Reconnect sync: sending current stats payload:', payload)
      this.matchSubscription.perform('send_stat', payload)
    } else {
      console.log('[ActionCable] Reconnect sync: no local stats to send.')
    }
  }
}
