import CodexBarCore import Foundation enum UsagePaceText { struct WeeklyDetail { let leftLabel: String let rightLabel: String? let expectedUsedPercent: Double let stage: UsagePace.Stage } static func weeklySummary(pace: UsagePace, now: Date = .init()) -> String { let detail = self.weeklyDetail(pace: pace, now: now) if let rightLabel = detail.rightLabel { return "Pace: \(detail.leftLabel) · \(rightLabel)" } return "Pace: \(detail.leftLabel)" } static func weeklyDetail(pace: UsagePace, now: Date = .init()) -> WeeklyDetail { 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? { let etaLabel: String? if pace.willLastToReset { etaLabel = "Lasts until reset" } else if let etaSeconds = pace.etaSeconds { let etaText = Self.durationText(seconds: etaSeconds, now: now) etaLabel = etaText == "now" ? "Runs out now" : "Runs out in \(etaText)" } else { etaLabel = nil } guard let runOutProbability = pace.runOutProbability else { return etaLabel } let roundedRisk = self.roundedRiskPercent(runOutProbability) let riskLabel = "≈ \(roundedRisk)% run-out risk" if let etaLabel { return "\(etaLabel) · \(riskLabel)" } return riskLabel } 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 } private static func roundedRiskPercent(_ probability: Double) -> Int { let percent = probability.clamped(to: 0...1) * 100 let rounded = (percent / 5).rounded() * 5 return Int(rounded) } }