import { getISODate, getWeekNumber } from "@/utils/dates"
import type { GoalProgress } from "./Goal"
import { GoalBooleanProgress, GoalNumericProgress } from "./Goal"
import type { Habit } from "./Habit"
import type { HabitProgress } from "./HabitProgress"

export interface HabitHistoryJSON {
  habit: Habit
  progressHistory: HabitProgress[]
}

export class HabitHistory implements HabitHistoryJSON {
  public habit: Habit

  private _progressHistory: HabitProgress[] = []

  public constructor(options: HabitHistoryJSON) {
    const { habit, progressHistory } = options
    this.habit = habit
    this.progressHistory = progressHistory
  }

  /**
   * Progress History sorted chronologically (from old to most recent progress at the end).
   */
  public get progressHistory(): HabitProgress[] {
    return this._progressHistory
  }

  public set progressHistory(progressHistory: HabitProgress[]) {
    this._progressHistory = [...progressHistory]
    this._progressHistory.sort((a, b) => {
      return a.date.getTime() - b.date.getTime()
    })
  }

  public getProgressesByDate(date: Date): HabitProgress[] {
    return this._progressHistory.filter((progress) => {
      if (this.habit.goal.frequency === "monthly") {
        return (
          date.getFullYear() === progress.date.getFullYear() &&
          date.getMonth() === progress.date.getMonth()
        )
      }
      if (this.habit.goal.frequency === "weekly") {
        return (
          getWeekNumber(date) === getWeekNumber(progress.date) &&
          date.getFullYear() === progress.date.getFullYear()
        )
      }
      if (this.habit.goal.frequency === "daily") {
        return getISODate(date) === getISODate(progress.date)
      }
      return false
    })
  }

  public getGoalProgressByDate(date: Date): GoalProgress {
    const progresses = this.getProgressesByDate(date)
    if (this.habit.goal.isBoolean()) {
      const lastSavedProgress = progresses[progresses.length - 1]
      return new GoalBooleanProgress({
        goal: this.habit.goal,
        progress: lastSavedProgress?.goalProgress?.isCompleted() ?? false,
      })
    }

    if (this.habit.goal.isNumeric()) {
      return new GoalNumericProgress({
        goal: this.habit.goal,
        progress: progresses.reduce((sum, current) => {
          const goalProgress = current.goalProgress as GoalNumericProgress
          return sum + goalProgress.progress
        }, 0),
      })
    }

    throw new Error("Invalid")
  }
}
