package me.khodak.claudeusage.data

data class UsageData(
    val messagesUsed: Int = -1,
    val messagesLimit: Int = -1,
    val messagesRemaining: Int = -1,
    val resetAtEpoch: Long = -1L,
    val isRateLimited: Boolean = false,
    val lastUpdated: Long = 0L,
    val errorMessage: String = "",
    val isLoggedIn: Boolean = false,
    val sessionStartEpoch: Long = 0L,
    val weeklyActiveDaysMask: Int = 0,   // bitmask: bit0=Sun, bit1=Mon ... bit6=Sat
    // From /api/organizations/{id}/usage — utilization as percentage 0-100
    val fiveHourUtilization: Float = -1f,
    val weeklyUtilization: Float = -1f,
    val utilizationResetAtEpoch: Long = -1L,
    val weeklyResetAtEpoch: Long = -1L
) {
    val hasRateLimitData: Boolean get() =
        messagesLimit > 0 || messagesRemaining >= 0 || fiveHourUtilization >= 0f

    val hasSessionData: Boolean get() = sessionStartEpoch > 0

    val progressPercent: Int get() = when {
        messagesLimit > 0 && effectiveUsed >= 0 ->
            ((effectiveUsed.toFloat() / messagesLimit.toFloat()) * 100).toInt().coerceIn(0, 100)
        fiveHourUtilization >= 0f -> fiveHourUtilization.toInt().coerceIn(0, 100)
        else -> 0
    }

    val effectiveUsed: Int get() = when {
        messagesUsed >= 0 -> messagesUsed
        messagesRemaining >= 0 && messagesLimit > 0 -> messagesLimit - messagesRemaining
        else -> -1
    }

    val effectiveRemaining: Int get() = when {
        messagesRemaining >= 0 -> messagesRemaining
        messagesUsed >= 0 && messagesLimit > 0 -> messagesLimit - messagesUsed
        else -> -1
    }

    val weeklyActiveDays: Int get() = Integer.bitCount(weeklyActiveDaysMask)

    /**
     * Session utilization as a 0-100 reading for the history chart, preferring the /usage
     * utilization endpoint and falling back to message-count progress. Returns -1f when there is
     * no usable reading — so message-only accounts (no utilization endpoint) still build history
     * instead of leaving the chart permanently on "Collecting history…".
     */
    val sessionReadingPct: Float get() = when {
        fiveHourUtilization >= 0f -> fiveHourUtilization
        messagesLimit > 0 && effectiveUsed >= 0 ->
            ((effectiveUsed.toFloat() / messagesLimit.toFloat()) * 100f).coerceIn(0f, 100f)
        else -> -1f
    }

    // The best reset time we have (utilization endpoint is preferred)
    val effectiveResetEpoch: Long get() = when {
        utilizationResetAtEpoch > 0 -> utilizationResetAtEpoch
        resetAtEpoch > 0 -> resetAtEpoch
        else -> -1L
    }

    /** True if this fetch produced any usable usage reading at all. */
    val hasAnyReading: Boolean get() =
        fiveHourUtilization >= 0f || weeklyUtilization >= 0f || hasRateLimitData

    /**
     * Merge a fresh fetch over the last cached reading so a failed or partial refresh never
     * blanks the widget. If this fetch got nothing usable, the whole previous snapshot is kept
     * (with its original timestamp, so the footer shows the data's true age). Otherwise each
     * metric this fetch didn't return falls back to the previous value.
     */
    fun mergedWith(previous: UsageData?): UsageData {
        if (previous == null || !previous.hasAnyReading) return this
        if (!hasAnyReading) {
            // Keep last-good data; only carry this attempt's login/session context forward.
            return previous.copy(
                isLoggedIn = isLoggedIn,
                sessionStartEpoch = if (sessionStartEpoch > 0) sessionStartEpoch else previous.sessionStartEpoch,
                weeklyActiveDaysMask = if (weeklyActiveDaysMask != 0) weeklyActiveDaysMask else previous.weeklyActiveDaysMask
            )
        }
        return copy(
            fiveHourUtilization = if (fiveHourUtilization >= 0f) fiveHourUtilization else previous.fiveHourUtilization,
            utilizationResetAtEpoch = if (fiveHourUtilization >= 0f) utilizationResetAtEpoch else previous.utilizationResetAtEpoch,
            weeklyUtilization = if (weeklyUtilization >= 0f) weeklyUtilization else previous.weeklyUtilization,
            weeklyResetAtEpoch = if (weeklyUtilization >= 0f) weeklyResetAtEpoch else previous.weeklyResetAtEpoch,
            messagesLimit = if (messagesLimit > 0) messagesLimit else previous.messagesLimit,
            messagesUsed = if (messagesUsed >= 0) messagesUsed else previous.messagesUsed,
            messagesRemaining = if (messagesRemaining >= 0) messagesRemaining else previous.messagesRemaining,
            resetAtEpoch = if (resetAtEpoch > 0) resetAtEpoch else previous.resetAtEpoch
        )
    }
}
