/**
 * Enum representing assessment types.
 * @enum {string}
 */
export enum AssessmentTypes {
  Fitness = 'fitness',
  Custom = 'custom',
  Body360 = 'body360',
}

/**
 * Enum representing UI elements that can be displayed during workouts.
 * @enum {string}
 */
export enum UIElement {
  RepsCounter = 'repsCounter',
  Timer = 'timer',
  GaugeOfMotion = 'gaugeOfMotion',
}

/**
 * Enum representing body zones targeted in workouts.
 * @enum {string}
 */
export enum BodyZone {
  UpperBody = 'UpperBody',
  LowerBody = 'LowerBody',
  FullBody = 'FullBody',
}

/**
 * Enum representing workout difficulty levels.
 * @enum {string}
 */
export enum WorkoutDifficulty {
  LowDifficulty = 'LowDifficulty',
  MidDifficulty = 'MidDifficulty',
  HighDifficulty = 'HighDifficulty',
}

/**
 * Enum representing workout durations.
 * @enum {string}
 */
export enum WorkoutDuration {
  Short = 'Short',
  Long = 'Long',
}

/**
 * Enum representing different types of scoring methods.
 * @enum {string}
 */
export enum ScoringType {
  Rom = 'rom',
  Time = 'time',
  Reps = 'reps',
}

/**
 * Enum representing gender options for user data.
 * @enum {string}
 */
export enum Gender {
  Female = 'Female',
  Male = 'Male',
  Other = 'Rather not say',
}

export enum Language {
  English = 'en',
  Hebrew = 'he',
}

/**
 * Enum representing the exercise rep counter prefrence.
 * @enum {string}
 */
export enum CounterPreferences {
  Default = 'Default',
  PerfectOnly = 'PerfectOnly',
}

/**
 * Enum representing the workout couser type.
 * @enum {string}
 */
export enum EndExercisePreferences {
  Default = 'Default', //on timer end
  TargetBased = 'TargetBased', //on target reached
}

/**
 * Class representing a workout.
 */
export class SMWorkout {
  /**
   * @param {string | null} id - Unique identifier for the workout.
   * @param {string | null} name - Name of the workout.
   * @param {string | null} workoutIntro - URL for workout intro sound.
   * @param {string | null} soundtrack - URL for soundtrack.
   * @param {SMExercise[]} exercises - List of exercises included in the workout.
   * @param {string | null} getInFrame - URL for body cal get in frame sound.
   * @param {string | null} bodycalFinished - URL for body cal finished sound.
   * @param {string | null} workoutClosure - URL for workout closure sound.
   */
  id: string | null;
  name: string | null;
  workoutIntro: string | null;
  soundtrack: string | null;
  exercises: SMExercise[];
  getInFrame: string | null;
  bodycalFinished: string | null;
  workoutClosure: string | null;

  constructor(
    id: string | null,
    name: string | null,
    workoutIntro: string | null,
    soundtrack: string | null,
    exercises: SMExercise[],
    getInFrame: string | null,
    bodycalFinished: string | null,
    workoutClosure: string | null
  ) {
    this.id = id || null;
    this.name = name || null;
    this.workoutIntro = workoutIntro || null;
    this.soundtrack = soundtrack || null;
    this.exercises = exercises;
    this.getInFrame = getInFrame || null;
    this.bodycalFinished = bodycalFinished || null;
    this.workoutClosure = workoutClosure || null;
  }

  toJson(): string {
    return JSON.stringify({
      id: this.id,
      name: this.name,
      workoutIntro: this.workoutIntro,
      soundtrack: this.soundtrack,
      exercises: this.exercises,
      getInFrame: this.getInFrame,
      bodycalFinished: this.bodycalFinished,
      workoutClosure: this.workoutClosure,
    });
  }
}

/**
 * Class representing an exercise in a workout.
 */
export class SMExercise {
  /**
   * @param {string | null} prettyName - Name of the exercise.
   * @param {number | null} totalSeconds - Duration of the exercise in seconds.
   * @param {string | null} videoInstruction - Video instruction URL.
   * @param {string | null} exerciseIntro - URL for exercise intro sound.
   * @param {UIElement[] | null} uiElements - List of UI elements for this exercise.
   * @param {string} detector - Name of the detector for tracking exercise movement.
   * @param {string | null} exerciseClosure - URL for exercise closer sound.
   * @param {SMScoringParams | null} scoringParams - Parameters for exercise scoring.
   */
  detector: string;
  uiElements: UIElement[] | null;
  videoInstruction: string | null;
  totalSeconds: number | null;
  prettyName: string | null;
  exerciseIntro: string | null;
  exerciseClosure: string | null;
  scoringParams: SMScoringParams | null;

  constructor(
    prettyName: string | null,
    totalSeconds: number | null,
    videoInstruction: string | null,
    exerciseIntro: string | null,
    uiElements: UIElement[] | null,
    detector: string,
    exerciseClosure: string | null,
    scoringParams: SMScoringParams | null
  ) {
    this.prettyName = prettyName || null;
    this.totalSeconds = totalSeconds || null;
    this.videoInstruction = videoInstruction || null;
    this.exerciseIntro = exerciseIntro || null;
    this.uiElements = uiElements || null;
    this.detector = detector;
    this.exerciseClosure = exerciseClosure || null;
    this.scoringParams = scoringParams || null;
  }
}

/**
 * Class representing an exercise in an assessment.
 */
export class SMAssessmentExercise extends SMExercise {
  /**
   * @param {string | null} prettyName - Name of the exercise.
   * @param {number | null} totalSeconds - Duration of the exercise in seconds.
   * @param {string | null} videoInstruction - Video instruction URL.
   * @param {string | null} exerciseIntro - URL for exercise intro sound.
   * @param {UIElement[] | null} uiElements - List of UI elements for this exercise.
   * @param {string} detector - Name of the detector for tracking exercise movement.
   * @param {string | null} exerciseClosure - URL for exercise closer sound.
   * @param {SMScoringParams | null} scoringParams - Parameters for exercise scoring.
   * @param {string | null} closureFailedSound - Applicable only for ClouserTarget.TargetBased, URL for exercise closure sound If you did not reach clouser target.
   * @param {string | null} summaryTitle - Title for the exercise summary.
   * @param {string | null} summarySubTitle - Subtitle for the exercise summary.
   * @param {string | null} summaryMainMetricTitle - Main metric title in the summary.
   * @param {string | null} summaryMainMetricSubTitle - Main metric subtitle in the summary.
   */

  closureFailedSound: string | null;
  summaryTitle: string | null;
  summarySubTitle: string | null;
  summaryMainMetricTitle: string | null;
  summaryMainMetricSubTitle: string | null;

  constructor(
    prettyName: string | null,
    totalSeconds: number | null,
    videoInstruction: string | null,
    exerciseIntro: string | null,
    uiElements: UIElement[] | null,
    detector: string,
    exerciseClosure: string | null,
    scoringParams: SMScoringParams | null,
    closureFailedSound: string | null,
    summaryTitle: string | null,
    summarySubTitle: string | null,
    summaryMainMetricTitle: string | null,
    summaryMainMetricSubTitle: string | null
  ) {
    // Call the constructor of the parent class (SMExercise)
    super(
      prettyName,
      totalSeconds,
      videoInstruction,
      exerciseIntro,
      uiElements,
      detector,
      exerciseClosure,
      scoringParams
    );

    // Set additional properties specific to SMAssessmentExercise
    this.closureFailedSound = closureFailedSound || null;
    this.summaryTitle = summaryTitle || null;
    this.summarySubTitle = summarySubTitle || null;
    this.summaryMainMetricTitle = summaryMainMetricTitle || null;
    this.summaryMainMetricSubTitle = summaryMainMetricSubTitle || null;
  }
}

/**
 * Class representing scoring parameters for an exercise.
 */
export class SMScoringParams {
  /**
   * @param {ScoringType | null} type - Type of scoring (e.g., ROM, time, reps).
   * @param {number | null} scoreFactor - Factor to adjust the score.
   * @param {number | null} targetTime - Target time for time-based scoring.
   * @param {number | null} targetReps - Target reps for rep-based scoring.
   * @param {string | null} targetRom - Range of motion target for ROM-based scoring.
   * @param {string[] | null} passCriteria - List of criteria required to pass.
   */
  type: ScoringType | null;
  scoreFactor: number | null;
  targetTime: number | null;
  targetReps: number | null;
  targetRom: string | null;
  passCriteria: string[] | null;

  constructor(
    type: ScoringType | null,
    scoreFactor: number | null,
    targetTime: number | null,
    targetReps: number | null,
    targetRom: string | null,
    passCriteria: string[] | null
  ) {
    this.type = type || null;
    this.scoreFactor = scoreFactor || null;
    this.targetTime = targetTime || null;
    this.targetReps = targetReps || null;
    this.targetRom = targetRom || null;
    this.passCriteria = passCriteria || null;
  }
}

/**
 * Class representing the configuration for a workout program.
 */
export class WorkoutConfig {
  /**
   * @param {number} week - Week number in the program.
   * @param {BodyZone} bodyZone - Targeted body zone for the workout.
   * @param {WorkoutDifficulty} difficultyLevel - Difficulty level of the workout.
   * @param {WorkoutDuration} workoutDuration - Duration of the workout.
   * @param {Language} language - The session language
   * @param {string} programID - Unique identifier for the workout program.
   */
  week: number;
  bodyZone: BodyZone;
  difficultyLevel: WorkoutDifficulty;
  workoutDuration: WorkoutDuration;
  language: Language;
  programID: string;

  constructor(
    week: number,
    bodyZone: BodyZone,
    difficultyLevel: WorkoutDifficulty,
    workoutDuration: WorkoutDuration,
    language: Language,
    programID: string
  ) {
    this.week = week;
    this.bodyZone = bodyZone;
    this.difficultyLevel = difficultyLevel;
    this.workoutDuration = workoutDuration;
    this.language = language;
    this.programID = programID;
  }

  toJson(): string {
    return JSON.stringify({
      week: this.week,
      bodyZone: this.bodyZone,
      difficultyLevel: this.difficultyLevel,
      workoutDuration: this.workoutDuration,
      language: this.language,
      programID: this.programID,
    });
  }
}

/**
 * Class representing user data.
 */
export class UserData {
  /**
   * @param {Gender} gender - User's gender.
   * @param {number} age - User's age.
   */
  gender: Gender;
  age: number;

  constructor(gender: Gender, age: number) {
    this.gender = gender;
    this.age = age;
  }

  toJson(): string {
    return JSON.stringify({
      gender: this.gender,
      age: this.age,
    });
  }
}
