namespace ClaudeOverview.Models;
///
/// Subscription usage pulled from the Claude /api/oauth/usage endpoint.
/// Percentages are 0–100.
///
public sealed class UsageInfo
{
/// Length of the rolling session-limit block (the API's "five_hour" bucket).
public static readonly TimeSpan SessionWindow = TimeSpan.FromHours(5);
public double SessionPercent { get; set; }
public DateTime? SessionResetsAt { get; set; }
/// UTC start of the current session-limit window (its reset time minus the 5-hour block).
public DateTime? SessionWindowStartUtc =>
SessionResetsAt is { } r ? r.ToUniversalTime() - SessionWindow : null;
public double WeeklyPercent { get; set; }
public DateTime? WeeklyResetsAt { get; set; }
public string? Error { get; set; }
public bool Ok => Error is null;
/// True when the last fetch was rejected with HTTP 429 (rate limited).
public bool RateLimited { get; set; }
/// Server-suggested wait before retrying (from the Retry-After header), if any.
public TimeSpan? RetryAfter { get; set; }
public static string ResetsIn(DateTime? resetsAtUtc)
{
if (resetsAtUtc is null) return "";
var span = resetsAtUtc.Value.ToUniversalTime() - DateTime.UtcNow;
if (span <= TimeSpan.Zero) return "resetting…";
if (span < TimeSpan.FromHours(1)) return $"resets in {(int)span.TotalMinutes}m";
if (span < TimeSpan.FromDays(1)) return $"resets in {(int)span.TotalHours}h{span.Minutes:00}m";
return $"resets in {(int)span.TotalDays}d{span.Hours}h";
}
}