package app.closer.domain.model

import java.time.LocalDate

/**
 * Models the different streak types tracked for a couple in Closer.
 *
 * All dates are [LocalDate] because streak days are bucketed by the user's local
 * calendar day (the app already uses a local date key for daily questions).
 */
sealed class Streak {

    /**
     * Total number of consecutive days or windows this streak has been active.
     * For [Couple] and [Personal] this is a count of consecutive days.
     * For [WeeklyRhythm] this is a count of consecutive 7-day windows.
     */
    abstract val count: Int

    /**
     * The most recent date that contributed to this streak, if any.
     */
    abstract val lastActiveDate: LocalDate?

    /**
     * True if the streak includes today. Used to decide whether a streak is
     * "alive" right now or just historical.
     */
    abstract val includesToday: Boolean

    /**
     * Both partners completed a shared action on the same local day.
     */
    data class Couple(
        override val count: Int = 0,
        override val lastActiveDate: LocalDate? = null,
        override val includesToday: Boolean = false
    ) : Streak()

    /**
     * The current user completed a private action on their own local day.
     */
    data class Personal(
        override val count: Int = 0,
        override val lastActiveDate: LocalDate? = null,
        override val includesToday: Boolean = false
    ) : Streak()

    /**
     * The couple completed at least [WEEKLY_RHYTHM_THRESHOLD] shared actions
     * in a rolling 7-day window.
     */
    data class WeeklyRhythm(
        override val count: Int = 0,
        override val lastActiveDate: LocalDate? = null,
        override val includesToday: Boolean = false
    ) : Streak() {
        companion object {
            const val WINDOW_DAYS = 7
            const val THRESHOLD = 3
        }
    }
}

/**
 * The outcome of calculating all streaks for the current user and their partner.
 *
 * @property coupleStreak both partners answered/completed a shared action today
 * @property personalStreak the current user answered/completed a private action today
 * @property weeklyRhythm couple completed 3+ shared actions in the last 7 days
 * @property milestoneCopy warm milestone text, or null when no milestone applies
 * @property canRepair true if a missed day can be repaired today
 * @property repairDueDate the last day that can be repaired, or null if none
 */
data class StreakResult(
    val coupleStreak: Streak.Couple,
    val personalStreak: Streak.Personal,
    val weeklyRhythm: Streak.WeeklyRhythm,
    val milestoneCopy: String? = null,
    val canRepair: Boolean = false,
    val repairDueDate: LocalDate? = null
)

/**
 * Raw input describing which local days each partner was active.
 *
 * @property userDates days the current user answered or completed a private action
 * @property partnerDates days the partner answered or completed a shared action
 * @property coupleActionDates days both partners completed a shared action
 * @property today the local date to evaluate against (injected for testability)
 * @property lastRepairDate the most recent local date a streak repair was used, if any
 */
data class StreakInput(
    val userDates: List<LocalDate>,
    val partnerDates: List<LocalDate>,
    val coupleActionDates: List<LocalDate>,
    val today: LocalDate,
    val lastRepairDate: LocalDate? = null
)
