import CodexBarCore import Foundation enum UsagePaceText { struct WeeklyDetail: Sendable { let leftLabel: String let rightLabel: String? let expectedUsedPercent: Double let stage: UsagePace.Stage } private static let minimumExpectedPercent: Double = 3 static func weeklySummary(provider: UsageProvider, window: RateWindow, now: Date = .init()) -> String? { guard let detail = weeklyDetail(provider: provider, window: window, now: now) else { return nil } if let rightLabel = detail.rightLabel { return "Pace: \(detail.leftLabel) ยท \(rightLabel)" } return "Pace: \(detail.leftLabel)" } static func weeklyDetail(provider: UsageProvider, window: RateWindow, now: Date = .init()) -> WeeklyDetail? { guard let pace = weeklyPace(provider: provider, window: window, now: now) else { return nil } return WeeklyDetail( leftLabel: Self.detailLeftLabel(for: pace), rightLabel: Self.detailRightLabel(for: pace, now: now), expectedUsedPercent: pace.expectedUsedPercent, stage: pace.stage) } private static func detailLeftLabel(for pace: UsagePace) -> String { let deltaValue = Int(abs(pace.deltaPercent).rounded()) switch pace.stage { case .onTrack: return "On pace" case .slightlyAhead, .ahead, .farAhead: return "\(deltaValue)% in deficit" case .slightlyBehind, .behind, .farBehind: return "\(deltaValue)% in reserve" } } private static func detailRightLabel(for pace: UsagePace, now: Date) -> String? { if pace.willLastToReset { return "Lasts until reset" } guard let etaSeconds = pace.etaSeconds else { return nil } let etaText = Self.durationText(seconds: etaSeconds, now: now) if etaText == "now" { return "Runs out now" } return "Runs out in \(etaText)" } private static func durationText(seconds: TimeInterval, now: Date) -> String { let date = now.addingTimeInterval(seconds) let countdown = UsageFormatter.resetCountdownDescription(from: date, now: now) if countdown == "now" { return "now" } if countdown.hasPrefix("in ") { return String(countdown.dropFirst(3)) } return countdown } static func weeklyPace(provider: UsageProvider, window: RateWindow, now: Date) -> UsagePace? { guard provider == .codex || provider == .claude else { return nil } guard window.remainingPercent > 0 else { return nil } guard let pace = UsagePace.weekly(window: window, now: now, defaultWindowMinutes: 10080) else { return nil } guard pace.expectedUsedPercent >= Self.minimumExpectedPercent else { return nil } return pace } }