import { describe, it, expect, beforeEach } from 'vitest'
import { PROGRAMS, ASSESSMENT_WORKOUT, ALL_PROGRAM_WORKOUTS, UPPER_BODY_WORKOUTS, LOWER_BODY_WORKOUTS, FULL_BODY_WORKOUTS } from '../../shared/data/programs'
import type { Program, ProgramId } from '../../shared/types/program'

describe('programs data', () => {
  const programIds: ProgramId[] = ['upper-body', 'lower-body', 'full-body']

  describe('PROGRAMS structure', () => {
    it('should have exactly 3 programs', () => {
      expect(Object.keys(PROGRAMS)).toHaveLength(3)
    })

    it('should have all required program IDs', () => {
      programIds.forEach(id => {
        expect(PROGRAMS[id]).toBeDefined()
      })
    })

    it('should have consistent program structure', () => {
      programIds.forEach(id => {
        const program = PROGRAMS[id]
        expect(program.id).toBe(id)
        expect(program.title).toBeDefined()
        expect(program.description).toBeDefined()
        expect(program.durationWeeks).toBe(4)
        expect(program.workoutsPerWeek).toBe(5)
        expect(program.totalWorkouts).toBe(20)
        expect(program.equipment).toBeDefined()
        expect(program.focusAreas).toBeDefined()
        expect(program.weeks).toHaveLength(4)
      })
    })
  })

  describe('program weeks', () => {
    it('should have 4 weeks per program', () => {
      programIds.forEach(id => {
        expect(PROGRAMS[id].weeks).toHaveLength(4)
      })
    })

    it('should have correct week numbers', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach((week, index) => {
          expect(week.weekNumber).toBe(index + 1)
        })
      })
    })

    it('should have 5 workouts per week', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          expect(week.workouts).toHaveLength(5)
        })
      })
    })

    it('should have correct week titles', () => {
      const expectedTitles = ['Foundation', 'Building', 'Challenge', 'Peak Performance']
      
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach((week, index) => {
          expect(week.title).toBe(expectedTitles[index])
        })
      })
    })

    it('should have week descriptions', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          expect(week.description).toBeDefined()
          expect(week.description.length).toBeGreaterThan(0)
        })
      })
    })

    it('should have week focus', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          expect(week.focus).toBeDefined()
          expect(week.focus.length).toBeGreaterThan(0)
        })
      })
    })
  })

  describe('workout structure', () => {
    it('should have 8 exercises per workout', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            expect(workout.exercises).toHaveLength(8)
          })
        })
      })
    })

    it('should have 4-minute duration for all workouts', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            expect(workout.duration).toBe(4)
          })
        })
      })
    })

    it('should have exercise names', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            workout.exercises.forEach(exercise => {
              expect(exercise.name).toBeDefined()
              expect(exercise.name.length).toBeGreaterThan(0)
            })
          })
        })
      })
    })

    it('should have 20-second exercise duration', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            workout.exercises.forEach(exercise => {
              expect(exercise.duration).toBe(20)
            })
          })
        })
      })
    })

    it('should have workout equipment', () => {
      let hasEquipment = false
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            if (workout.equipment && workout.equipment.length > 0) {
              hasEquipment = true
            }
          })
        })
      })
      expect(hasEquipment).toBe(true)
    })

    it('should have workout focus areas', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            expect(workout.focus).toBeDefined()
            expect(workout.focus.length).toBeGreaterThan(0)
          })
        })
      })
    })

    it('should have workout tips', () => {
      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            expect(workout.tips).toBeDefined()
            expect(workout.tips.length).toBeGreaterThan(0)
          })
        })
      })
    })
  })

  describe('workout IDs', () => {
    it('should have unique workout IDs', () => {
      const allIds = new Set<string>()
      let duplicateFound = false

      programIds.forEach(id => {
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            if (allIds.has(workout.id)) {
              duplicateFound = true
            }
            allIds.add(workout.id)
          })
        })
      })

      expect(duplicateFound).toBe(false)
    })

    it('should follow ID naming convention', () => {
      const patterns = {
        'upper-body': /^ub-w\d-d\d$/,
        'lower-body': /^lb-w\d-d\d$/,
        'full-body': /^fb-w\d-d\d$/,
      }

      programIds.forEach(id => {
        const pattern = patterns[id]
        PROGRAMS[id].weeks.forEach(week => {
          week.workouts.forEach(workout => {
            expect(workout.id).toMatch(pattern)
          })
        })
      })
    })
  })

  describe('equipment requirements', () => {
    it('should have required equipment for upper body', () => {
      expect(PROGRAMS['upper-body'].equipment.required).toContain('Resistance band')
    })

    it('should have required equipment for lower body', () => {
      expect(PROGRAMS['lower-body'].equipment.required).toContain('Resistance band')
    })

    it('should have no required equipment for full body', () => {
      expect(PROGRAMS['full-body'].equipment.required).toHaveLength(0)
    })
  })

  describe('focus areas', () => {
    it('should have upper body focus areas', () => {
      const focus = PROGRAMS['upper-body'].focusAreas
      expect(focus).toContain('Shoulders')
      expect(focus).toContain('Chest')
      expect(focus).toContain('Back')
    })

    it('should have lower body focus areas', () => {
      const focus = PROGRAMS['lower-body'].focusAreas
      expect(focus).toContain('Legs')
      expect(focus).toContain('Glutes')
    })

    it('should have full body focus areas', () => {
      const focus = PROGRAMS['full-body'].focusAreas
      expect(focus).toContain('Total Body')
      expect(focus).toContain('Core')
    })
  })

  describe('ALL_PROGRAM_WORKOUTS', () => {
    it('should contain all workouts from all programs', () => {
      expect(ALL_PROGRAM_WORKOUTS).toHaveLength(60)
    })

    it('should combine upper, lower, and full body workouts', () => {
      expect(UPPER_BODY_WORKOUTS).toHaveLength(20)
      expect(LOWER_BODY_WORKOUTS).toHaveLength(20)
      expect(FULL_BODY_WORKOUTS).toHaveLength(20)
    })
  })

  describe('ASSESSMENT_WORKOUT', () => {
    it('should have correct structure', () => {
      expect(ASSESSMENT_WORKOUT.id).toBe('initial-assessment')
      expect(ASSESSMENT_WORKOUT.title).toBe('Movement Assessment')
      expect(ASSESSMENT_WORKOUT.duration).toBe(4)
    })

    it('should have 8 exercises', () => {
      expect(ASSESSMENT_WORKOUT.exercises).toHaveLength(8)
    })

    it('should have exercise purposes', () => {
      ASSESSMENT_WORKOUT.exercises.forEach(exercise => {
        expect(exercise.purpose).toBeDefined()
        expect(exercise.purpose.length).toBeGreaterThan(0)
      })
    })

    it('should have tips', () => {
      expect(ASSESSMENT_WORKOUT.tips).toBeDefined()
      expect(ASSESSMENT_WORKOUT.tips.length).toBeGreaterThan(0)
    })
  })
})
