/**
 * TabataFit Program Store
 * Handles program selection, progression tracking, and sequential unlocking
 */

import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import AsyncStorage from '@react-native-async-storage/async-storage'
import type {
  ProgramId,
  ProgramWorkout,
  ProgramProgress,
  AssessmentResult,
} from '../types/program'
import { PROGRAMS } from '../data/programs'

interface ProgramState {
  // Program selection
  selectedProgramId: ProgramId | null
  
  // Progress tracking for each program
  programsProgress: Record<ProgramId, ProgramProgress>
  
  // Assessment
  assessment: {
    isCompleted: boolean
    result: AssessmentResult | null
  }
  
  // Actions
  selectProgram: (programId: ProgramId) => void
  completeWorkout: (programId: ProgramId, workoutId: string) => void
  completeAssessment: (result: AssessmentResult) => void
  skipAssessment: () => void
  resetProgram: (programId: ProgramId) => void
  changeProgram: (programId: ProgramId) => void
  
  // Getters
  getCurrentWorkout: (programId: ProgramId) => ProgramWorkout | null
  getNextWorkout: (programId: ProgramId) => ProgramWorkout | null
  isWeekUnlocked: (programId: ProgramId, weekNumber: number) => boolean
  isWorkoutUnlocked: (programId: ProgramId, workoutId: string) => boolean
  getProgramCompletion: (programId: ProgramId) => number
  getTotalWorkoutsCompleted: () => number
  getProgramStatus: (programId: ProgramId) => 'not-started' | 'in-progress' | 'completed'
  getRecommendedNextWorkout: () => { programId: ProgramId; workout: ProgramWorkout } | null
}

const createInitialProgress = (programId: ProgramId): ProgramProgress => ({
  programId,
  currentWeek: 1,
  currentWorkoutIndex: 0,
  completedWorkoutIds: [],
  isProgramCompleted: false,
  startDate: undefined,
  lastWorkoutDate: undefined,
})

export const useProgramStore = create<ProgramState>()(
  persist(
    (set, get) => ({
      // Initial state
      selectedProgramId: null,
      programsProgress: {
        'upper-body': createInitialProgress('upper-body'),
        'lower-body': createInitialProgress('lower-body'),
        'full-body': createInitialProgress('full-body'),
      },
      assessment: {
        isCompleted: false,
        result: null,
      },

      // Select a program to start
      selectProgram: (programId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        
        // If starting for the first time, set start date
        if (progress.completedWorkoutIds.length === 0 && !progress.startDate) {
          set((state) => ({
            selectedProgramId: programId,
            programsProgress: {
              ...state.programsProgress,
              [programId]: {
                ...progress,
                startDate: new Date().toISOString(),
              },
            },
          }))
        } else {
          set({ selectedProgramId: programId })
        }
      },

      // Complete a workout and advance progress
      completeWorkout: (programId, workoutId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        const program = PROGRAMS[programId]
        
        if (!program) return

        // Add to completed list
        const newCompletedIds = [...progress.completedWorkoutIds, workoutId]
        
        // Find current workout position
        let newWeek = progress.currentWeek
        let newWorkoutIndex = progress.currentWorkoutIndex
        
        // Check if we completed the last workout of the week
        const currentWeekWorkouts = program.weeks[progress.currentWeek - 1]?.workouts || []
        const isLastWorkoutOfWeek = progress.currentWorkoutIndex >= currentWeekWorkouts.length - 1
        
        if (isLastWorkoutOfWeek && progress.currentWeek < 4) {
          // Move to next week
          newWeek = (progress.currentWeek + 1) as 1 | 2 | 3 | 4
          newWorkoutIndex = 0
        } else if (!isLastWorkoutOfWeek) {
          // Move to next workout in same week
          newWorkoutIndex = progress.currentWorkoutIndex + 1
        }
        
        // Check if program is completed (all 20 workouts)
        const isProgramCompleted = newCompletedIds.length >= 20
        
        set((state) => ({
          programsProgress: {
            ...state.programsProgress,
            [programId]: {
              ...progress,
              completedWorkoutIds: newCompletedIds,
              currentWeek: newWeek,
              currentWorkoutIndex: newWorkoutIndex,
              isProgramCompleted,
              lastWorkoutDate: new Date().toISOString(),
            },
          },
        }))
      },

      // Complete assessment
      completeAssessment: (result) => {
        set({
          assessment: {
            isCompleted: true,
            result,
          },
        })
      },

      // Skip assessment
      skipAssessment: () => {
        set({
          assessment: {
            isCompleted: true,
            result: null,
          },
        })
      },

      // Reset a program to start over
      resetProgram: (programId) => {
        set((state) => ({
          programsProgress: {
            ...state.programsProgress,
            [programId]: createInitialProgress(programId),
          },
          selectedProgramId: state.selectedProgramId === programId ? null : state.selectedProgramId,
        }))
      },

      // Change to a different program (allow switching)
      changeProgram: (programId) => {
        set({ selectedProgramId: programId })
      },

      // Get the current workout for a program
      getCurrentWorkout: (programId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        const program = PROGRAMS[programId]
        
        if (!program || !progress) return null
        
        const week = program.weeks[progress.currentWeek - 1]
        if (!week) return null
        
        return week.workouts[progress.currentWorkoutIndex] || null
      },

      // Get the next workout (for displaying what's coming up)
      getNextWorkout: (programId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        const program = PROGRAMS[programId]
        
        if (!program || !progress) return null
        
        const currentWeek = program.weeks[progress.currentWeek - 1]
        if (!currentWeek) return null
        
        // Check if there's another workout in the current week
        if (progress.currentWorkoutIndex < currentWeek.workouts.length - 1) {
          return currentWeek.workouts[progress.currentWorkoutIndex + 1]
        }
        
        // Check if there's a next week
        if (progress.currentWeek < 4) {
          const nextWeek = program.weeks[progress.currentWeek]
          return nextWeek?.workouts[0] || null
        }
        
        return null
      },

      // Check if a week is unlocked
      isWeekUnlocked: (programId, weekNumber) => {
        const state = get()
        const progress = state.programsProgress[programId]
        
        // Week 1 is always unlocked
        if (weekNumber === 1) return true
        
        // Check if all workouts from previous week are completed
        const program = PROGRAMS[programId]
        if (!program) return false
        
        const previousWeek = program.weeks[weekNumber - 2]
        if (!previousWeek) return false
        
        const previousWeekWorkoutIds = previousWeek.workouts.map((w) => w.id)
        return previousWeekWorkoutIds.every((id) =>
          progress.completedWorkoutIds.includes(id)
        )
      },

      // Check if a specific workout is unlocked
      isWorkoutUnlocked: (programId, workoutId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        const program = PROGRAMS[programId]
        
        if (!program || !progress) return false
        
        // Find the workout in the program structure
        for (const week of program.weeks) {
          const workoutIndex = week.workouts.findIndex((w) => w.id === workoutId)
          if (workoutIndex === -1) continue
          
          // If it's in week 1, it's unlocked
          if (week.weekNumber === 1) {
            // Check if it's before or at current position
            if (week.weekNumber === progress.currentWeek) {
              return workoutIndex <= progress.currentWorkoutIndex
            }
            return true
          }
          
          // Check if the week is unlocked
          if (!get().isWeekUnlocked(programId, week.weekNumber)) {
            return false
          }
          
          // Check if it's before or at current position
          if (week.weekNumber === progress.currentWeek) {
            return workoutIndex <= progress.currentWorkoutIndex
          }
          
          // If it's in a previous week, it's unlocked
          if (week.weekNumber < progress.currentWeek) {
            return true
          }
        }
        
        return false
      },

      // Get completion percentage for a program
      getProgramCompletion: (programId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        if (!progress) return 0
        
        return Math.round((progress.completedWorkoutIds.length / 20) * 100)
      },

      // Get total workouts completed across all programs
      getTotalWorkoutsCompleted: () => {
        const state = get()
        return Object.values(state.programsProgress).reduce(
          (total, progress) => total + progress.completedWorkoutIds.length,
          0
        )
      },

      // Get program status
      getProgramStatus: (programId) => {
        const state = get()
        const progress = state.programsProgress[programId]
        
        if (!progress || progress.completedWorkoutIds.length === 0) {
          return 'not-started'
        }
        
        if (progress.isProgramCompleted) {
          return 'completed'
        }
        
        return 'in-progress'
      },

      // Get recommended next workout (for home screen)
      getRecommendedNextWorkout: () => {
        const state = get()
        
        // If a program is selected, recommend the next workout in that program
        if (state.selectedProgramId) {
          const nextWorkout = get().getCurrentWorkout(state.selectedProgramId)
          if (nextWorkout) {
            return {
              programId: state.selectedProgramId,
              workout: nextWorkout,
            }
          }
        }
        
        // Find any in-progress program
        for (const programId of Object.keys(PROGRAMS) as ProgramId[]) {
          const status = get().getProgramStatus(programId)
          if (status === 'in-progress') {
            const nextWorkout = get().getCurrentWorkout(programId)
            if (nextWorkout) {
              return { programId, workout: nextWorkout }
            }
          }
        }
        
        return null
      },
    }),
    {
      name: 'tabatafit-program-storage',
      storage: {
        getItem: async (name) => {
          const value = await AsyncStorage.getItem(name)
          return value ? JSON.parse(value) : null
        },
        setItem: async (name, value) => {
          await AsyncStorage.setItem(name, JSON.stringify(value))
        },
        removeItem: async (name) => {
          await AsyncStorage.removeItem(name)
        },
      },
    }
  )
)
