import Foundation // MARK: - Amount Response Models struct DeepSeekAmountPayload: Decodable { let code: Int? let msg: String? let data: DeepSeekAmountData? private enum CodingKeys: String, CodingKey { case code, msg, data } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.code = try container.decodeIfPresent(Int.self, forKey: .code) self.msg = try container.decodeIfPresent(String.self, forKey: .msg) if container.contains(.data) { if let dataValue = try? container.decodeIfPresent(DeepSeekAmountData.self, forKey: .data) { self.data = dataValue } else { self.data = nil } } else { self.data = nil } }} struct DeepSeekAmountData: Decodable { let bizCode: Int? let bizMsg: String? let bizData: DeepSeekAmountBizData? private enum CodingKeys: String, CodingKey { case bizCode = "biz_code" case bizMsg = "biz_msg" case bizData = "biz_data" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.bizCode = try container.decodeIfPresent(Int.self, forKey: .bizCode) self.bizMsg = try container.decodeIfPresent(String.self, forKey: .bizMsg) if container.contains(.bizData) { if let dataValue = try? container.decodeIfPresent(DeepSeekAmountBizData.self, forKey: .bizData) { self.bizData = dataValue } else { self.bizData = nil } } else { self.bizData = nil } }} struct DeepSeekAmountBizData: Decodable { let total: [DeepSeekModelUsage]? let days: [DeepSeekDayUsage]? private enum CodingKeys: String, CodingKey { case total, days }} // MARK: - Cost Response Models struct DeepSeekCostPayload: Decodable { let code: Int? let msg: String? let data: DeepSeekCostData? private enum CodingKeys: String, CodingKey { case code, msg, data } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.code = try container.decodeIfPresent(Int.self, forKey: .code) self.msg = try container.decodeIfPresent(String.self, forKey: .msg) if container.contains(.data) { if let dataValue = try? container.decodeIfPresent(DeepSeekCostData.self, forKey: .data) { self.data = dataValue } else { self.data = nil } } else { self.data = nil } }} struct DeepSeekCostData: Decodable { let bizCode: Int? let bizMsg: String? let bizData: [DeepSeekCostBizDataItem]? private enum CodingKeys: String, CodingKey { case bizCode = "biz_code" case bizMsg = "biz_msg" case bizData = "biz_data" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.bizCode = try container.decodeIfPresent(Int.self, forKey: .bizCode) self.bizMsg = try container.decodeIfPresent(String.self, forKey: .bizMsg) self.bizData = try container.decodeIfPresent([DeepSeekCostBizDataItem].self, forKey: .bizData) }} struct DeepSeekCostBizDataItem: Decodable { let total: [DeepSeekCostModelUsage]? let days: [DeepSeekCostDayUsage]? let currency: String? private enum CodingKeys: String, CodingKey { case total, days, currency }} // MARK: - Shared Models struct DeepSeekModelUsage: Decodable { let model: String? let usage: [DeepSeekUsageItem]? private enum CodingKeys: String, CodingKey { case model, usage }} struct DeepSeekDayUsage: Decodable { let date: String? let data: [DeepSeekModelUsage]? private enum CodingKeys: String, CodingKey { case date, data }} struct DeepSeekUsageItem: Decodable { let type: String? let amount: String? private enum CodingKeys: String, CodingKey { case type, amount }} struct DeepSeekCostModelUsage: Decodable { let model: String? let usage: [DeepSeekCostItem]? private enum CodingKeys: String, CodingKey { case model, usage }} struct DeepSeekCostDayUsage: Decodable { let date: String? let data: [DeepSeekCostModelUsage]? private enum CodingKeys: String, CodingKey { case date, data }} struct DeepSeekCostItem: Decodable { let type: String? let amount: String? private enum CodingKeys: String, CodingKey { case type, amount }} // MARK: - Domain Models public struct DeepSeekUsageSummary: Sendable, Equatable { public let todayTokens: Int public let currentMonthTokens: Int public let todayCost: Double? public let currentMonthCost: Double? public let requestCount: Int public let currentMonthRequestCount: Int public let topModel: String? public let categoryBreakdown: [DeepSeekCategoryBreakdown] public let daily: [DeepSeekDailyUsage] public let currency: String public let updatedAt: Date public init( todayTokens: Int, currentMonthTokens: Int, todayCost: Double?, currentMonthCost: Double?, requestCount: Int, currentMonthRequestCount: Int, topModel: String?, categoryBreakdown: [DeepSeekCategoryBreakdown], daily: [DeepSeekDailyUsage], currency: String, updatedAt: Date) { self.todayTokens = todayTokens self.currentMonthTokens = currentMonthTokens self.todayCost = todayCost self.currentMonthCost = currentMonthCost self.requestCount = requestCount self.currentMonthRequestCount = currentMonthRequestCount self.topModel = topModel self.categoryBreakdown = categoryBreakdown self.daily = daily self.currency = currency self.updatedAt = updatedAt }} public struct DeepSeekCategoryBreakdown: Sendable, Equatable { public let category: DeepSeekUsageCategory public let tokens: Int public let cost: Double? public init(category: DeepSeekUsageCategory, tokens: Int, cost: Double?) { self.category = category self.tokens = tokens self.cost = cost }} public enum DeepSeekUsageCategory: String, Sendable, Equatable { case promptCacheHitToken = "PROMPT_CACHE_HIT_TOKEN" case promptCacheMissToken = "PROMPT_CACHE_MISS_TOKEN" case responseToken = "RESPONSE_TOKEN" case request = "REQUEST" public init?(rawValue: String) { switch rawValue.uppercased() { case "PROMPT_CACHE_HIT_TOKEN": self = .promptCacheHitToken case "PROMPT_CACHE_MISS_TOKEN": self = .promptCacheMissToken case "RESPONSE_TOKEN": self = .responseToken case "REQUEST": self = .request default: return nil } }} public struct DeepSeekDailyUsage: Sendable, Equatable { public let date: String public let totalTokens: Int public let cost: Double? public let requestCount: Int public init(date: String, totalTokens: Int, cost: Double?, requestCount: Int) { self.date = date self.totalTokens = totalTokens self.cost = cost self.requestCount = requestCount }} // MARK: - Parsing enum DeepSeekUsageCostParser { static func decodeAmountPayload(data: Data) throws -> DeepSeekAmountPayload { try JSONDecoder().decode(DeepSeekAmountPayload.self, from: data) } static func decodeCostPayload(data: Data) throws -> DeepSeekCostPayload { try JSONDecoder().decode(DeepSeekCostPayload.self, from: data) } static func parse( amountData: Data, costData: Data, now: Date = Date(), calendar: Calendar = .current) throws -> DeepSeekUsageSummary { let amountPayload: DeepSeekAmountPayload let costPayload: DeepSeekCostPayload do { amountPayload = try self.decodeAmountPayload(data: amountData) } catch { throw DeepSeekUsageError.parseFailed("amount: \(error.localizedDescription)") } do { costPayload = try self.decodeCostPayload(data: costData) } catch { throw DeepSeekUsageError.parseFailed("cost: \(error.localizedDescription)") } // Validate responses if let code = amountPayload.code, code != 0 { throw DeepSeekUsageError.apiError("amount code \(code)") } if let bizCode = amountPayload.data?.bizCode, bizCode != 0 { throw DeepSeekUsageError.apiError("amount biz_code \(bizCode)") } if let code = costPayload.code, code != 0 { throw DeepSeekUsageError.apiError("cost code \(code)") } if let bizCode = costPayload.data?.bizCode, bizCode != 0 { throw DeepSeekUsageError.apiError("cost biz_code \(bizCode)") } guard let amountBizData = amountPayload.data?.bizData else { throw DeepSeekUsageError.parseFailed("Missing amount biz_data") } let currency = costPayload.data?.bizData?.first?.currency ?? "CNY" // Parse total amounts let totalAmounts = amountBizData.total ?? [] let totalCosts = costPayload.data?.bizData?.first?.total ?? [] // Parse daily data let dailyAmounts = amountBizData.days ?? [] let dailyCosts = costPayload.data?.bizData?.first?.days ?? [] return self.aggregate(input: AggregationInput( totalAmounts: totalAmounts, totalCosts: totalCosts, dailyAmounts: dailyAmounts, dailyCosts: dailyCosts, currency: currency, now: now, calendar: calendar)) } // MARK: - Aggregation private struct AggregationContext { let calendar: Calendar let todayString: String let startOfMonth: Date let now: Date let dailyAmountMap: [String: [String: [DeepSeekUsageItem]]] let dailyCostMap: [String: [String: [DeepSeekCostItem]]] let allDates: Set<String> init( dailyAmounts: [DeepSeekDayUsage], dailyCosts: [DeepSeekCostDayUsage], now: Date, calendar: Calendar) { self.calendar = calendar self.now = now self.todayString = Self.dayString(now, calendar: calendar) var components = calendar.dateComponents([.year, .month], from: now) components.day = 1 self.startOfMonth = calendar.date(from: components) ?? now self.dailyAmountMap = Self.buildAmountMap(from: dailyAmounts) self.dailyCostMap = Self.buildCostMap(from: dailyCosts) var dates: Set<String> = [] for date in self.dailyAmountMap.keys { dates.insert(date) } for date in self.dailyCostMap.keys { dates.insert(date) } self.allDates = dates } static func dayString(_ date: Date, calendar: Calendar) -> String { let components = calendar.dateComponents([.year, .month, .day], from: date) guard let year = components.year, let month = components.month, let day = components.day else { return "" } return String(format: "%04d-%02d-%02d", year, month, day) } static func buildAmountMap( from dailyAmounts: [DeepSeekDayUsage]) -> [String: [String: [DeepSeekUsageItem]]] { var result: [String: [String: [DeepSeekUsageItem]]] = [:] for dayUsage in dailyAmounts { guard let date = dayUsage.date else { continue } var modelMap: [String: [DeepSeekUsageItem]] = [:] for modelUsage in dayUsage.data ?? [] { guard let model = modelUsage.model else { continue } let items = modelUsage.usage ?? [] if !items.isEmpty { modelMap[model] = items } } if !modelMap.isEmpty { result[date] = modelMap } } return result } static func buildCostMap( from dailyCosts: [DeepSeekCostDayUsage]) -> [String: [String: [DeepSeekCostItem]]] { var result: [String: [String: [DeepSeekCostItem]]] = [:] for dayUsage in dailyCosts { guard let date = dayUsage.date else { continue } var modelMap: [String: [DeepSeekCostItem]] = [:] for modelUsage in dayUsage.data ?? [] { guard let model = modelUsage.model else { continue } let items = modelUsage.usage ?? [] if !items.isEmpty { modelMap[model] = items } } if !modelMap.isEmpty { result[date] = modelMap } } return result } } private struct AggregationInput { let totalAmounts: [DeepSeekModelUsage] let totalCosts: [DeepSeekCostModelUsage] let dailyAmounts: [DeepSeekDayUsage] let dailyCosts: [DeepSeekCostDayUsage] let currency: String let now: Date let calendar: Calendar } private static func aggregate(input: AggregationInput) -> DeepSeekUsageSummary { let ctx = AggregationContext( dailyAmounts: input.dailyAmounts, dailyCosts: input.dailyCosts, now: input.now, calendar: input.calendar) // Today aggregation let todayResult = self.aggregateDay( dateString: ctx.todayString, amountMap: ctx.dailyAmountMap, costMap: ctx.dailyCostMap, calendar: ctx.calendar) // Month aggregation let dailyCtx = DailyAggregationContext( allDates: ctx.allDates, startOfMonth: ctx.startOfMonth, now: ctx.now, amountMap: ctx.dailyAmountMap, costMap: ctx.dailyCostMap, calendar: ctx.calendar) let monthResult = self.aggregateMonth(ctx: dailyCtx) // Model and category breakdown from totals let (topModel, categoryBreakdown) = self.buildBreakdowns( totalAmounts: input.totalAmounts, totalCosts: input.totalCosts) // Daily usage array let dailyUsages = self.buildDailyUsages(ctx: dailyCtx) return DeepSeekUsageSummary( todayTokens: todayResult.tokens, currentMonthTokens: monthResult.tokens, todayCost: todayResult.cost, currentMonthCost: monthResult.cost, requestCount: todayResult.requests, currentMonthRequestCount: monthResult.requests, topModel: topModel, categoryBreakdown: categoryBreakdown, daily: dailyUsages, currency: input.currency, updatedAt: input.now) } private struct DayAggregationResult { let tokens: Int let cost: Double? let requests: Int } private struct DailyAggregationContext { let allDates: Set<String> let startOfMonth: Date let now: Date let amountMap: [String: [String: [DeepSeekUsageItem]]] let costMap: [String: [String: [DeepSeekCostItem]]] let calendar: Calendar } private static func aggregateDay( dateString: String, amountMap: [String: [String: [DeepSeekUsageItem]]], costMap: [String: [String: [DeepSeekCostItem]]],Lines 1–500 of 709. Load more
import Foundation // MARK: - Amount Response Models struct DeepSeekAmountPayload: Decodable { let code: Int? let msg: String? let data: DeepSeekAmountData? private enum CodingKeys: String, CodingKey { case code, msg, data } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.code = try container.decodeIfPresent(Int.self, forKey: .code) self.msg = try container.decodeIfPresent(String.self, forKey: .msg) if container.contains(.data) { if let dataValue = try? container.decodeIfPresent(DeepSeekAmountData.self, forKey: .data) { self.data = dataValue } else { self.data = nil } } else { self.data = nil } } } struct DeepSeekAmountData: Decodable { let bizCode: Int? let bizMsg: String? let bizData: DeepSeekAmountBizData? private enum CodingKeys: String, CodingKey { case bizCode = "biz_code" case bizMsg = "biz_msg" case bizData = "biz_data" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.bizCode = try container.decodeIfPresent(Int.self, forKey: .bizCode) self.bizMsg = try container.decodeIfPresent(String.self, forKey: .bizMsg) if container.contains(.bizData) { if let dataValue = try? container.decodeIfPresent(DeepSeekAmountBizData.self, forKey: .bizData) { self.bizData = dataValue } else { self.bizData = nil } } else { self.bizData = nil } } } struct DeepSeekAmountBizData: Decodable { let total: [DeepSeekModelUsage]? let days: [DeepSeekDayUsage]? private enum CodingKeys: String, CodingKey { case total, days } } // MARK: - Cost Response Models struct DeepSeekCostPayload: Decodable { let code: Int? let msg: String? let data: DeepSeekCostData? private enum CodingKeys: String, CodingKey { case code, msg, data } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.code = try container.decodeIfPresent(Int.self, forKey: .code) self.msg = try container.decodeIfPresent(String.self, forKey: .msg) if container.contains(.data) { if let dataValue = try? container.decodeIfPresent(DeepSeekCostData.self, forKey: .data) { self.data = dataValue } else { self.data = nil } } else { self.data = nil } } } struct DeepSeekCostData: Decodable { let bizCode: Int? let bizMsg: String? let bizData: [DeepSeekCostBizDataItem]? private enum CodingKeys: String, CodingKey { case bizCode = "biz_code" case bizMsg = "biz_msg" case bizData = "biz_data" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.bizCode = try container.decodeIfPresent(Int.self, forKey: .bizCode) self.bizMsg = try container.decodeIfPresent(String.self, forKey: .bizMsg) self.bizData = try container.decodeIfPresent([DeepSeekCostBizDataItem].self, forKey: .bizData) } } struct DeepSeekCostBizDataItem: Decodable { let total: [DeepSeekCostModelUsage]? let days: [DeepSeekCostDayUsage]? let currency: String? private enum CodingKeys: String, CodingKey { case total, days, currency } } // MARK: - Shared Models struct DeepSeekModelUsage: Decodable { let model: String? let usage: [DeepSeekUsageItem]? private enum CodingKeys: String, CodingKey { case model, usage } } struct DeepSeekDayUsage: Decodable { let date: String? let data: [DeepSeekModelUsage]? private enum CodingKeys: String, CodingKey { case date, data } } struct DeepSeekUsageItem: Decodable { let type: String? let amount: String? private enum CodingKeys: String, CodingKey { case type, amount } } struct DeepSeekCostModelUsage: Decodable { let model: String? let usage: [DeepSeekCostItem]? private enum CodingKeys: String, CodingKey { case model, usage } } struct DeepSeekCostDayUsage: Decodable { let date: String? let data: [DeepSeekCostModelUsage]? private enum CodingKeys: String, CodingKey { case date, data } } struct DeepSeekCostItem: Decodable { let type: String? let amount: String? private enum CodingKeys: String, CodingKey { case type, amount } } // MARK: - Domain Models public struct DeepSeekUsageSummary: Sendable, Equatable { public let todayTokens: Int public let currentMonthTokens: Int public let todayCost: Double? public let currentMonthCost: Double? public let requestCount: Int public let currentMonthRequestCount: Int public let topModel: String? public let categoryBreakdown: [DeepSeekCategoryBreakdown] public let daily: [DeepSeekDailyUsage] public let currency: String public let updatedAt: Date public init( todayTokens: Int, currentMonthTokens: Int, todayCost: Double?, currentMonthCost: Double?, requestCount: Int, currentMonthRequestCount: Int, topModel: String?, categoryBreakdown: [DeepSeekCategoryBreakdown], daily: [DeepSeekDailyUsage], currency: String, updatedAt: Date) { self.todayTokens = todayTokens self.currentMonthTokens = currentMonthTokens self.todayCost = todayCost self.currentMonthCost = currentMonthCost self.requestCount = requestCount self.currentMonthRequestCount = currentMonthRequestCount self.topModel = topModel self.categoryBreakdown = categoryBreakdown self.daily = daily self.currency = currency self.updatedAt = updatedAt } } public struct DeepSeekCategoryBreakdown: Sendable, Equatable { public let category: DeepSeekUsageCategory public let tokens: Int public let cost: Double? public init(category: DeepSeekUsageCategory, tokens: Int, cost: Double?) { self.category = category self.tokens = tokens self.cost = cost } } public enum DeepSeekUsageCategory: String, Sendable, Equatable { case promptCacheHitToken = "PROMPT_CACHE_HIT_TOKEN" case promptCacheMissToken = "PROMPT_CACHE_MISS_TOKEN" case responseToken = "RESPONSE_TOKEN" case request = "REQUEST" public init?(rawValue: String) { switch rawValue.uppercased() { case "PROMPT_CACHE_HIT_TOKEN": self = .promptCacheHitToken case "PROMPT_CACHE_MISS_TOKEN": self = .promptCacheMissToken case "RESPONSE_TOKEN": self = .responseToken case "REQUEST": self = .request default: return nil } } } public struct DeepSeekDailyUsage: Sendable, Equatable { public let date: String public let totalTokens: Int public let cost: Double? public let requestCount: Int public init(date: String, totalTokens: Int, cost: Double?, requestCount: Int) { self.date = date self.totalTokens = totalTokens self.cost = cost self.requestCount = requestCount } } // MARK: - Parsing enum DeepSeekUsageCostParser { static func decodeAmountPayload(data: Data) throws -> DeepSeekAmountPayload { try JSONDecoder().decode(DeepSeekAmountPayload.self, from: data) } static func decodeCostPayload(data: Data) throws -> DeepSeekCostPayload { try JSONDecoder().decode(DeepSeekCostPayload.self, from: data) } static func parse( amountData: Data, costData: Data, now: Date = Date(), calendar: Calendar = .current) throws -> DeepSeekUsageSummary { let amountPayload: DeepSeekAmountPayload let costPayload: DeepSeekCostPayload do { amountPayload = try self.decodeAmountPayload(data: amountData) } catch { throw DeepSeekUsageError.parseFailed("amount: \(error.localizedDescription)") } do { costPayload = try self.decodeCostPayload(data: costData) } catch { throw DeepSeekUsageError.parseFailed("cost: \(error.localizedDescription)") } // Validate responses if let code = amountPayload.code, code != 0 { throw DeepSeekUsageError.apiError("amount code \(code)") } if let bizCode = amountPayload.data?.bizCode, bizCode != 0 { throw DeepSeekUsageError.apiError("amount biz_code \(bizCode)") } if let code = costPayload.code, code != 0 { throw DeepSeekUsageError.apiError("cost code \(code)") } if let bizCode = costPayload.data?.bizCode, bizCode != 0 { throw DeepSeekUsageError.apiError("cost biz_code \(bizCode)") } guard let amountBizData = amountPayload.data?.bizData else { throw DeepSeekUsageError.parseFailed("Missing amount biz_data") } let currency = costPayload.data?.bizData?.first?.currency ?? "CNY" // Parse total amounts let totalAmounts = amountBizData.total ?? [] let totalCosts = costPayload.data?.bizData?.first?.total ?? [] // Parse daily data let dailyAmounts = amountBizData.days ?? [] let dailyCosts = costPayload.data?.bizData?.first?.days ?? [] return self.aggregate(input: AggregationInput( totalAmounts: totalAmounts, totalCosts: totalCosts, dailyAmounts: dailyAmounts, dailyCosts: dailyCosts, currency: currency, now: now, calendar: calendar)) } // MARK: - Aggregation private struct AggregationContext { let calendar: Calendar let todayString: String let startOfMonth: Date let now: Date let dailyAmountMap: [String: [String: [DeepSeekUsageItem]]] let dailyCostMap: [String: [String: [DeepSeekCostItem]]] let allDates: Set<String> init( dailyAmounts: [DeepSeekDayUsage], dailyCosts: [DeepSeekCostDayUsage], now: Date, calendar: Calendar) { self.calendar = calendar self.now = now self.todayString = Self.dayString(now, calendar: calendar) var components = calendar.dateComponents([.year, .month], from: now) components.day = 1 self.startOfMonth = calendar.date(from: components) ?? now self.dailyAmountMap = Self.buildAmountMap(from: dailyAmounts) self.dailyCostMap = Self.buildCostMap(from: dailyCosts) var dates: Set<String> = [] for date in self.dailyAmountMap.keys { dates.insert(date) } for date in self.dailyCostMap.keys { dates.insert(date) } self.allDates = dates } static func dayString(_ date: Date, calendar: Calendar) -> String { let components = calendar.dateComponents([.year, .month, .day], from: date) guard let year = components.year, let month = components.month, let day = components.day else { return "" } return String(format: "%04d-%02d-%02d", year, month, day) } static func buildAmountMap( from dailyAmounts: [DeepSeekDayUsage]) -> [String: [String: [DeepSeekUsageItem]]] { var result: [String: [String: [DeepSeekUsageItem]]] = [:] for dayUsage in dailyAmounts { guard let date = dayUsage.date else { continue } var modelMap: [String: [DeepSeekUsageItem]] = [:] for modelUsage in dayUsage.data ?? [] { guard let model = modelUsage.model else { continue } let items = modelUsage.usage ?? [] if !items.isEmpty { modelMap[model] = items } } if !modelMap.isEmpty { result[date] = modelMap } } return result } static func buildCostMap( from dailyCosts: [DeepSeekCostDayUsage]) -> [String: [String: [DeepSeekCostItem]]] { var result: [String: [String: [DeepSeekCostItem]]] = [:] for dayUsage in dailyCosts { guard let date = dayUsage.date else { continue } var modelMap: [String: [DeepSeekCostItem]] = [:] for modelUsage in dayUsage.data ?? [] { guard let model = modelUsage.model else { continue } let items = modelUsage.usage ?? [] if !items.isEmpty { modelMap[model] = items } } if !modelMap.isEmpty { result[date] = modelMap } } return result } } private struct AggregationInput { let totalAmounts: [DeepSeekModelUsage] let totalCosts: [DeepSeekCostModelUsage] let dailyAmounts: [DeepSeekDayUsage] let dailyCosts: [DeepSeekCostDayUsage] let currency: String let now: Date let calendar: Calendar } private static func aggregate(input: AggregationInput) -> DeepSeekUsageSummary { let ctx = AggregationContext( dailyAmounts: input.dailyAmounts, dailyCosts: input.dailyCosts, now: input.now, calendar: input.calendar) // Today aggregation let todayResult = self.aggregateDay( dateString: ctx.todayString, amountMap: ctx.dailyAmountMap, costMap: ctx.dailyCostMap, calendar: ctx.calendar) // Month aggregation let dailyCtx = DailyAggregationContext( allDates: ctx.allDates, startOfMonth: ctx.startOfMonth, now: ctx.now, amountMap: ctx.dailyAmountMap, costMap: ctx.dailyCostMap, calendar: ctx.calendar) let monthResult = self.aggregateMonth(ctx: dailyCtx) // Model and category breakdown from totals let (topModel, categoryBreakdown) = self.buildBreakdowns( totalAmounts: input.totalAmounts, totalCosts: input.totalCosts) // Daily usage array let dailyUsages = self.buildDailyUsages(ctx: dailyCtx) return DeepSeekUsageSummary( todayTokens: todayResult.tokens, currentMonthTokens: monthResult.tokens, todayCost: todayResult.cost, currentMonthCost: monthResult.cost, requestCount: todayResult.requests, currentMonthRequestCount: monthResult.requests, topModel: topModel, categoryBreakdown: categoryBreakdown, daily: dailyUsages, currency: input.currency, updatedAt: input.now) } private struct DayAggregationResult { let tokens: Int let cost: Double? let requests: Int } private struct DailyAggregationContext { let allDates: Set<String> let startOfMonth: Date let now: Date let amountMap: [String: [String: [DeepSeekUsageItem]]] let costMap: [String: [String: [DeepSeekCostItem]]] let calendar: Calendar } private static func aggregateDay( dateString: String, amountMap: [String: [String: [DeepSeekUsageItem]]], costMap: [String: [String: [DeepSeekCostItem]]],