84 lines
2.9 KiB
Swift
84 lines
2.9 KiB
Swift
import Foundation
|
|
|
|
public struct CrofUsageSnapshot: Sendable {
|
|
private static let requestWindowMinutes = 24 * 60
|
|
private static let resetTimeZone = TimeZone(identifier: "America/Chicago") ?? TimeZone(secondsFromGMT: -5)!
|
|
|
|
public let credits: Double
|
|
public let requestsPlan: Double
|
|
public let usableRequests: Double
|
|
public let updatedAt: Date
|
|
|
|
public init(
|
|
credits: Double,
|
|
requestsPlan: Double,
|
|
usableRequests: Double,
|
|
updatedAt: Date = Date())
|
|
{
|
|
self.credits = credits
|
|
self.requestsPlan = requestsPlan
|
|
self.usableRequests = usableRequests
|
|
self.updatedAt = updatedAt
|
|
}
|
|
|
|
public func toUsageSnapshot() -> UsageSnapshot {
|
|
let usedPercent: Double
|
|
if self.requestsPlan > 0 {
|
|
let usableRequests = max(0, min(self.requestsPlan, self.usableRequests))
|
|
let remainingPercent = floor(usableRequests / self.requestsPlan * 100).clamped(to: 0...100)
|
|
usedPercent = 100 - remainingPercent
|
|
} else {
|
|
usedPercent = 100
|
|
}
|
|
|
|
let primary = RateWindow(
|
|
usedPercent: usedPercent,
|
|
windowMinutes: Self.requestWindowMinutes,
|
|
resetsAt: Self.nextRequestReset(after: self.updatedAt),
|
|
resetDescription: Self.formatRequestsLeft(self.usableRequests))
|
|
|
|
let creditsDetail = Self.formatCredits(self.credits)
|
|
let secondary = RateWindow(
|
|
// Crof returns a balance but no credit cap, so the bar only indicates present vs. exhausted credits.
|
|
usedPercent: self.credits > 0 ? 0 : 100,
|
|
windowMinutes: nil,
|
|
resetsAt: nil,
|
|
resetDescription: creditsDetail)
|
|
|
|
return UsageSnapshot(
|
|
primary: primary,
|
|
secondary: secondary,
|
|
providerCost: nil,
|
|
updatedAt: self.updatedAt,
|
|
identity: ProviderIdentitySnapshot(
|
|
providerID: .crof,
|
|
accountEmail: nil,
|
|
accountOrganization: nil,
|
|
loginMethod: "API key"))
|
|
}
|
|
|
|
private static func formatCredits(_ value: Double) -> String {
|
|
let clamped = max(0, value)
|
|
let cents = floor(clamped * 100) / 100
|
|
return String(format: "$%.2f", cents)
|
|
}
|
|
|
|
private static func formatRequestsLeft(_ value: Double) -> String {
|
|
let clamped = max(0, value)
|
|
let formatted = clamped.rounded() == clamped
|
|
? String(format: "%.0f", clamped)
|
|
: String(format: "%.2f", clamped)
|
|
return "\(formatted) requests left"
|
|
}
|
|
|
|
private static func nextRequestReset(after date: Date) -> Date? {
|
|
var calendar = Calendar(identifier: .gregorian)
|
|
calendar.timeZone = Self.resetTimeZone
|
|
|
|
let startOfDay = calendar.startOfDay(for: date)
|
|
return startOfDay <= date
|
|
? calendar.date(byAdding: .day, value: 1, to: startOfDay)
|
|
: startOfDay
|
|
}
|
|
}
|