/**
 * Tabata Timer Hook
 * Multi-block timer supporting warmup, tabata blocks, inter-block rest, and cooldown
 *
 * State machine:
 * WARMUP → BLOCK(WORK↔REST × rounds) → INTER_BLOCK_REST → next block → COOLDOWN → COMPLETE
 */

import { useRef, useEffect, useCallback, useMemo } from 'react'
import { create } from 'zustand'
import type { TabataSession, TabataExercise, TabataTimerPhase, TabataBlock, TimedMovement } from '../types/program'

// ─── Tabata Player Store ─────────────────────────────────────────

interface TabataPlayerState {
  session: TabataSession | null
  phase: TabataTimerPhase
  timeRemaining: number
  currentBlockIndex: number
  currentRound: number
  currentWarmupIndex: number
  currentCooldownIndex: number
  isPaused: boolean
  isRunning: boolean
  calories: number
  startedAt: number | null

  loadSession: (session: TabataSession) => void
  setPhase: (phase: TabataTimerPhase) => void
  setTimeRemaining: (time: number) => void
  setCurrentBlock: (index: number) => void
  setCurrentRound: (round: number) => void
  setWarmupIndex: (index: number) => void
  setCooldownIndex: (index: number) => void
  setPaused: (paused: boolean) => void
  setRunning: (running: boolean) => void
  addCalories: (amount: number) => void
  reset: () => void
}

const INITIAL_STATE = {
  session: null as TabataSession | null,
  phase: 'WARMUP' as TabataTimerPhase,
  timeRemaining: 0,
  currentBlockIndex: 0,
  currentRound: 1,
  currentWarmupIndex: 0,
  currentCooldownIndex: 0,
  isPaused: false,
  isRunning: false,
  calories: 0,
  startedAt: null as number | null,
}

export const useTabataPlayerStore = create<TabataPlayerState>((set) => ({
  ...INITIAL_STATE,

  loadSession: (session) =>
    set({
      session,
      phase: 'WARMUP',
      timeRemaining: session.warmup.movements[0]?.duration ?? 0,
      currentBlockIndex: 0,
      currentRound: 1,
      currentWarmupIndex: 0,
      currentCooldownIndex: 0,
      isPaused: false,
      isRunning: false,
      calories: 0,
      startedAt: null,
    }),

  setPhase: (phase) => set({ phase }),
  setTimeRemaining: (time) => set({ timeRemaining: time }),
  setCurrentBlock: (index) => set({ currentBlockIndex: index }),
  setCurrentRound: (round) => set({ currentRound: round }),
  setWarmupIndex: (index) => set({ currentWarmupIndex: index }),
  setCooldownIndex: (index) => set({ currentCooldownIndex: index }),
  setPaused: (paused) => set({ isPaused: paused }),
  setRunning: (running) =>
    set((state) => ({
      isRunning: running,
      startedAt: running && !state.startedAt ? Date.now() : state.startedAt,
    })),
  addCalories: (amount) => set((state) => ({ calories: state.calories + amount })),
  reset: () => set(INITIAL_STATE),
}))

// ─── Hook Return Type ──────────────────────────────────────────

export interface UseTabataTimerReturn {
  phase: TabataTimerPhase
  timeRemaining: number
  currentRound: number
  totalRounds: number
  currentBlockIndex: number
  totalBlocks: number
  currentExercise: TabataExercise | null
  nextExercise: TabataExercise | null
  currentConseil: string
  isOddRound: boolean
  progress: number
  isPaused: boolean
  isRunning: boolean
  isComplete: boolean
  calories: number
  currentWarmupMovement: TimedMovement | null
  currentCooldownMovement: TimedMovement | null
  start: () => void
  pause: () => void
  resume: () => void
  skip: () => void
  stop: () => void
}

// ─── Constants ─────────────────────────────────────────────────

const INTER_BLOCK_REST_SECONDS = 60

// ─── Hook ──────────────────────────────────────────────────────

export function useTabataTimer(session: TabataSession | null): UseTabataTimerReturn {
  const store = useTabataPlayerStore()
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)

  // Load session on mount
  useEffect(() => {
    if (session) {
      store.loadSession(session)
    }
    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current)
    }
  }, [session?.id])

  const s = session
  const currentBlock: TabataBlock | null = s?.blocks[store.currentBlockIndex] ?? null

  // ─── Computed values ─────────────────────────────────────────

  const isOddRound = store.currentRound % 2 === 1

  const currentExercise: TabataExercise | null = useMemo(() => {
    if (!currentBlock) return null
    return isOddRound ? currentBlock.oddExercise : currentBlock.evenExercise
  }, [currentBlock, isOddRound])

  const currentConseil = currentExercise?.conseil ?? ''

  const nextExercise: TabataExercise | null = useMemo(() => {
    if (!currentBlock) return null
    const nextOdd = !isOddRound
    return nextOdd ? currentBlock.oddExercise : currentBlock.evenExercise
  }, [currentBlock, isOddRound])

  const totalRounds = s?.totalRounds ?? 0

  const progress = useMemo(() => {
    if (!s || store.phase === 'COMPLETE') return 1
    if (store.phase === 'WARMUP' || store.phase === 'COOLDOWN') return 0

    // Progress across all blocks
    const completedBlockRounds = store.currentBlockIndex * (currentBlock?.rounds ?? 8)
    const total = s.totalRounds
    if (total === 0) return 0
    return (completedBlockRounds + store.currentRound - 1) / total
  }, [s, store.phase, store.currentBlockIndex, store.currentRound, currentBlock])

  const currentWarmupMovement: TimedMovement | null =
    s?.warmup.movements[store.currentWarmupIndex] ?? null

  const currentCooldownMovement: TimedMovement | null =
    s?.cooldown.movements[store.currentCooldownIndex] ?? null

  // ─── Phase durations ─────────────────────────────────────────

  const phaseDuration = useMemo(() => {
    switch (store.phase) {
      case 'WARMUP':
        return currentWarmupMovement?.duration ?? 0
      case 'WORK':
        return currentBlock?.workTime ?? 20
      case 'REST':
        return currentBlock?.restTime ?? 10
      case 'INTER_BLOCK_REST':
        return INTER_BLOCK_REST_SECONDS
      case 'COOLDOWN':
        return currentCooldownMovement?.duration ?? 0
      case 'COMPLETE':
        return 0
    }
  }, [store.phase, currentBlock, currentWarmupMovement, currentCooldownMovement])

  // ─── Timer tick ──────────────────────────────────────────────
  // Uses recursive setTimeout so the last second (showing "1")
  // only holds for 600ms before transitioning, instead of the full 1000ms.

  useEffect(() => {
    if (!store.isRunning || store.isPaused || store.phase === 'COMPLETE' || !s) {
      if (intervalRef.current) {
        clearTimeout(intervalRef.current)
        intervalRef.current = null
      }
      return
    }

    function scheduleTick() {
      const state = useTabataPlayerStore.getState()
      const isLastSecond = state.timeRemaining <= 1.9
      const delay = isLastSecond ? 600 : 1000

      intervalRef.current = setTimeout(() => {
        const curState = useTabataPlayerStore.getState()
        if (!curState.isRunning || curState.isPaused || curState.phase === 'COMPLETE' || !s) return

        if (curState.timeRemaining <= 1.9) {
          transitionPhase(curState, s)
          // Don't reschedule — phase change triggers effect re-run
        } else {
          useTabataPlayerStore.getState().setTimeRemaining(curState.timeRemaining - 1)
          scheduleTick()
        }
      }, delay)
    }

    scheduleTick()

    return () => {
      if (intervalRef.current) {
        clearTimeout(intervalRef.current)
        intervalRef.current = null
      }
    }
  }, [store.isRunning, store.isPaused, store.phase, s?.id])

  // ─── Phase transitions ───────────────────────────────────────

  function transitionPhase(state: TabataPlayerState, session: TabataSession) {
    const { phase, currentBlockIndex, currentRound } = state
    const block = session.blocks[currentBlockIndex]

    switch (phase) {
      case 'WARMUP': {
        const nextIdx = state.currentWarmupIndex + 1
        if (nextIdx < session.warmup.movements.length) {
          // Next warmup movement
          useTabataPlayerStore.getState().setWarmupIndex(nextIdx)
          useTabataPlayerStore.getState().setTimeRemaining(session.warmup.movements[nextIdx].duration)
        } else {
          // Warmup done → start first block
          useTabataPlayerStore.getState().setPhase('WORK')
          useTabataPlayerStore.getState().setTimeRemaining(block?.workTime ?? 20)
        }
        break
      }

      case 'WORK': {
        // Add calories
        const caloriesPerRound = session.calories / session.totalRounds
        useTabataPlayerStore.getState().addCalories(Math.round(caloriesPerRound))

        useTabataPlayerStore.getState().setPhase('REST')
        useTabataPlayerStore.getState().setTimeRemaining(block?.restTime ?? 10)
        break
      }

      case 'REST': {
        const blockRounds = block?.rounds ?? 8
        if (currentRound >= blockRounds) {
          // Block complete
          const nextBlockIdx = currentBlockIndex + 1
          if (nextBlockIdx < session.blocks.length) {
            // Inter-block rest
            useTabataPlayerStore.getState().setPhase('INTER_BLOCK_REST')
            useTabataPlayerStore.getState().setTimeRemaining(INTER_BLOCK_REST_SECONDS)
            useTabataPlayerStore.getState().setCurrentBlock(nextBlockIdx)
            useTabataPlayerStore.getState().setCurrentRound(1)
          } else {
            // All blocks done → cooldown
            useTabataPlayerStore.getState().setPhase('COOLDOWN')
            useTabataPlayerStore.getState().setTimeRemaining(session.cooldown.movements[0]?.duration ?? 0)
            useTabataPlayerStore.getState().setCooldownIndex(0)
          }
        } else {
          // Next round in same block
          useTabataPlayerStore.getState().setPhase('WORK')
          useTabataPlayerStore.getState().setTimeRemaining(block?.workTime ?? 20)
          useTabataPlayerStore.getState().setCurrentRound(currentRound + 1)
        }
        break
      }

      case 'INTER_BLOCK_REST': {
        useTabataPlayerStore.getState().setPhase('WORK')
        useTabataPlayerStore.getState().setTimeRemaining(
          session.blocks[currentBlockIndex]?.workTime ?? 20
        )
        break
      }

      case 'COOLDOWN': {
        const nextIdx = state.currentCooldownIndex + 1
        if (nextIdx < session.cooldown.movements.length) {
          useTabataPlayerStore.getState().setCooldownIndex(nextIdx)
          useTabataPlayerStore.getState().setTimeRemaining(session.cooldown.movements[nextIdx].duration)
        } else {
          // Complete
          useTabataPlayerStore.getState().setPhase('COMPLETE')
          useTabataPlayerStore.getState().setTimeRemaining(0)
          useTabataPlayerStore.getState().setRunning(false)
        }
        break
      }
    }
  }

  // ─── Controls ────────────────────────────────────────────────

  const start = useCallback(() => {
    store.setRunning(true)
    store.setPaused(false)
  }, [])

  const pause = useCallback(() => {
    store.setPaused(true)
  }, [])

  const resume = useCallback(() => {
    store.setPaused(false)
  }, [])

  const skip = useCallback(() => {
    const state = useTabataPlayerStore.getState()
    if (!s) return

    switch (state.phase) {
      case 'WARMUP':
        // Skip to first block WORK
        useTabataPlayerStore.getState().setPhase('WORK')
        useTabataPlayerStore.getState().setTimeRemaining(s.blocks[0]?.workTime ?? 20)
        break
      case 'WORK':
        useTabataPlayerStore.getState().setPhase('REST')
        useTabataPlayerStore.getState().setTimeRemaining(currentBlock?.restTime ?? 10)
        break
      case 'REST':
        transitionPhase(state, s)
        break
      case 'INTER_BLOCK_REST':
        useTabataPlayerStore.getState().setPhase('WORK')
        useTabataPlayerStore.getState().setTimeRemaining(
          s.blocks[state.currentBlockIndex]?.workTime ?? 20
        )
        break
      case 'COOLDOWN':
        useTabataPlayerStore.getState().setPhase('COMPLETE')
        useTabataPlayerStore.getState().setTimeRemaining(0)
        useTabataPlayerStore.getState().setRunning(false)
        break
    }
  }, [s, currentBlock])

  const stop = useCallback(() => {
    useTabataPlayerStore.getState().reset()
  }, [])

  return {
    phase: store.phase,
    timeRemaining: store.timeRemaining,
    currentRound: store.currentRound,
    totalRounds,
    currentBlockIndex: store.currentBlockIndex,
    totalBlocks: s?.blocks.length ?? 0,
    currentExercise,
    nextExercise,
    currentConseil,
    isOddRound,
    progress,
    isPaused: store.isPaused,
    isRunning: store.isRunning,
    isComplete: store.phase === 'COMPLETE',
    calories: store.calories,
    currentWarmupMovement,
    currentCooldownMovement,
    start,
    pause,
    resume,
    skip,
    stop,
  }
}
