import CodexBarCore
import Foundation

enum HistoricalUsageWindowKind: String, Codable {
    case secondary
}

enum HistoricalUsageRecordSource: String, Codable {
    case live
    case backfill
}

struct HistoricalUsageRecord: Codable {
    let v: Int
    let provider: UsageProvider
    let windowKind: HistoricalUsageWindowKind
    let source: HistoricalUsageRecordSource
    let accountKey: String?
    let sampledAt: Date
    let usedPercent: Double
    let resetsAt: Date
    let windowMinutes: Int

    init(
        v: Int,
        provider: UsageProvider,
        windowKind: HistoricalUsageWindowKind,
        source: HistoricalUsageRecordSource,
        accountKey: String?,
        sampledAt: Date,
        usedPercent: Double,
        resetsAt: Date,
        windowMinutes: Int)
    {
        self.v = v
        self.provider = provider
        self.windowKind = windowKind
        self.source = source
        self.accountKey = accountKey
        self.sampledAt = sampledAt
        self.usedPercent = usedPercent
        self.resetsAt = resetsAt
        self.windowMinutes = windowMinutes
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.v = try container.decodeIfPresent(Int.self, forKey: .v) ?? 1
        self.provider = try container.decode(UsageProvider.self, forKey: .provider)
        self.windowKind = try container.decode(HistoricalUsageWindowKind.self, forKey: .windowKind)
        self.source = try container.decodeIfPresent(HistoricalUsageRecordSource.self, forKey: .source) ?? .live
        self.accountKey = try container.decodeIfPresent(String.self, forKey: .accountKey)
        self.sampledAt = try container.decode(Date.self, forKey: .sampledAt)
        self.usedPercent = try container.decode(Double.self, forKey: .usedPercent)
        self.resetsAt = try container.decode(Date.self, forKey: .resetsAt)
        self.windowMinutes = try container.decode(Int.self, forKey: .windowMinutes)
    }
}

struct HistoricalWeekProfile {
    let resetsAt: Date
    let windowMinutes: Int
    let curve: [Double]
}

struct CodexHistoricalDataset {
    static let gridPointCount = 169
    let weeks: [HistoricalWeekProfile]
}

actor HistoricalUsageHistoryStore {
    private static let schemaVersion = 1
    private static let writeInterval: TimeInterval = 30 * 60
    private static let writeDeltaThreshold: Double = 1
    private static let retentionDays: TimeInterval = 56 * 24 * 60 * 60
    private static let minimumWeekSamples = 6
    private static let boundaryCoverageWindow: TimeInterval = 24 * 60 * 60
    private static let backfillWindowCapWeeks = 8
    private static let backfillCalibrationMinimumUsedPercent = 1.0
    private static let backfillCalibrationMinimumCredits = 0.001
    private static let backfillSampleFractions: [Double] = (0...14).map { Double($0) / 14.0 }
    private static let coverageTolerance: TimeInterval = 16 * 60 * 60
    private static let resetBucketSeconds: TimeInterval = 5 * 60

    private let fileURL: URL
    private var records: [HistoricalUsageRecord] = []
    private var loaded = false

    init(fileURL: URL? = nil) {
        self.fileURL = fileURL ?? HistoricalUsageHistoryStore.defaultFileURL()
    }

    func loadCodexDataset(accountKey: String?) -> CodexHistoricalDataset? {
        self.ensureLoaded()
        return self.buildDataset(accountKey: accountKey)
    }

    func loadCodexDataset(
        canonicalAccountKey: String?,
        canonicalEmailHashKey: String?,
        legacyEmailHash: String?,
        hasAdjacentMultiAccountVeto: Bool) -> CodexHistoricalDataset?
    {
        self.ensureLoaded()
        return self.buildDataset(
            canonicalAccountKey: canonicalAccountKey,
            canonicalEmailHashKey: canonicalEmailHashKey,
            legacyEmailHash: legacyEmailHash,
            hasAdjacentMultiAccountVeto: hasAdjacentMultiAccountVeto)
    }

    func recordCodexWeekly(
        window: RateWindow,
        sampledAt: Date = .init(),
        accountKey: String?) -> CodexHistoricalDataset?
    {
        guard let rawResetsAt = window.resetsAt else { return self.loadCodexDataset(accountKey: accountKey) }
        guard let windowMinutes = window.windowMinutes, windowMinutes > 0 else {
            return self.loadCodexDataset(accountKey: accountKey)
        }
        self.ensureLoaded()
        let resetsAt = Self.normalizeReset(rawResetsAt)

        let sample = HistoricalUsageRecord(
            v: Self.schemaVersion,
            provider: .codex, // Provider-specific by design: this store persists live Codex weekly-window samples.
            windowKind: .secondary,
            source: .live,
            accountKey: accountKey,
            sampledAt: sampledAt,
            usedPercent: Self.clamp(window.usedPercent, lower: 0, upper: 100),
            resetsAt: resetsAt,
            windowMinutes: windowMinutes)

        if !self.shouldAccept(sample) {
            return self.buildDataset(accountKey: accountKey)
        }

        self.records.append(sample)
        self.pruneOldRecords(now: sampledAt)
        self.records.sort { lhs, rhs in
            if lhs.sampledAt == rhs.sampledAt {
                if lhs.resetsAt == rhs.resetsAt {
                    return lhs.usedPercent < rhs.usedPercent
                }
                return lhs.resetsAt < rhs.resetsAt
            }
            return lhs.sampledAt < rhs.sampledAt
        }
        self.persist()
        return self.buildDataset(accountKey: accountKey)
    }

    func backfillCodexWeeklyFromUsageBreakdown(
        _ breakdown: [OpenAIDashboardDailyBreakdown],
        referenceWindow: RateWindow,
        now: Date = .init(),
        accountKey: String?) -> CodexHistoricalDataset?
    {
        self.ensureLoaded()
        let existingDataset = self.buildDataset(accountKey: accountKey)

        guard let rawResetsAt = referenceWindow.resetsAt else { return existingDataset }
        guard let windowMinutes = referenceWindow.windowMinutes, windowMinutes > 0 else { return existingDataset }
        let resetsAt = Self.normalizeReset(rawResetsAt)

        let duration = TimeInterval(windowMinutes) * 60
        guard duration > 0 else { return existingDataset }

        let windowStart = resetsAt.addingTimeInterval(-duration)
        let calibrationEnd = Self.clampDate(now, lower: windowStart, upper: resetsAt)
        let dayUsages = Self.parseDayUsages(
            from: breakdown,
            asOf: calibrationEnd,
            fillingFrom: windowStart)
        guard !dayUsages.isEmpty else { return existingDataset }
        guard let coverageStart = dayUsages.first?.start, let coverageEnd = dayUsages.last?.end else {
            return existingDataset
        }
        guard coverageStart <= windowStart.addingTimeInterval(Self.coverageTolerance) else {
            return existingDataset
        }
        guard coverageEnd >= calibrationEnd.addingTimeInterval(-Self.coverageTolerance) else {
            return existingDataset
        }

        let currentUsedPercent = Self.clamp(referenceWindow.usedPercent, lower: 0, upper: 100)
        guard currentUsedPercent >= Self.backfillCalibrationMinimumUsedPercent else { return existingDataset }

        let currentCredits = Self.creditsUsed(
            from: dayUsages,
            between: windowStart,
            and: calibrationEnd)
        guard currentCredits > Self.backfillCalibrationMinimumCredits else { return existingDataset }

        let estimatedCreditsAtLimit = currentCredits / (currentUsedPercent / 100)
        guard estimatedCreditsAtLimit.isFinite, estimatedCreditsAtLimit > Self.backfillCalibrationMinimumCredits else {
            return existingDataset
        }

        struct RecordKey: Hashable {
            let resetsAt: Date
            let sampledAt: Date
            let windowMinutes: Int
            let accountKey: String?
        }

        var synthesized: [HistoricalUsageRecord] = []
        synthesized.reserveCapacity(Self.backfillWindowCapWeeks * Self.backfillSampleFractions.count)

        for weeksBack in 1...Self.backfillWindowCapWeeks {
            let reset = Self.normalizeReset(resetsAt.addingTimeInterval(-duration * Double(weeksBack)))
            let start = reset.addingTimeInterval(-duration)
            guard start >= coverageStart.addingTimeInterval(-Self.coverageTolerance),
                  reset <= coverageEnd.addingTimeInterval(Self.coverageTolerance)
            else {
                continue
            }

            let existingForWeek = self.records.filter {
                $0.provider == .codex &&
                    $0.windowKind == .secondary &&
                    $0.windowMinutes == windowMinutes &&
                    $0.accountKey == accountKey &&
                    $0.resetsAt == reset
            }
            if Self.isCompleteWeek(samples: existingForWeek, windowStart: start, resetsAt: reset) {
                continue
            }
            var existingRecordKeys = Set(existingForWeek.map {
                RecordKey(
                    resetsAt: $0.resetsAt,
                    sampledAt: $0.sampledAt,
                    windowMinutes: $0.windowMinutes,
                    accountKey: $0.accountKey)
            })

            let weekCredits = Self.creditsUsed(from: dayUsages, between: start, and: reset)
            guard weekCredits > Self.backfillCalibrationMinimumCredits else { continue }

            for fraction in Self.backfillSampleFractions {
                let sampledAt = start.addingTimeInterval(duration * fraction)
                let recordKey = RecordKey(
                    resetsAt: reset,
                    sampledAt: sampledAt,
                    windowMinutes: windowMinutes,
                    accountKey: accountKey)
                guard !existingRecordKeys.contains(recordKey) else { continue }
                let cumulativeCredits = Self.creditsUsed(from: dayUsages, between: start, and: sampledAt)
                let usedPercent = Self.clamp((cumulativeCredits / estimatedCreditsAtLimit) * 100, lower: 0, upper: 100)
                synthesized.append(HistoricalUsageRecord(
                    v: Self.schemaVersion,
                    provider: .codex, // Provider-specific by design: this path backfills Codex weekly history.
                    windowKind: .secondary,
                    source: .backfill,
                    accountKey: accountKey,
                    sampledAt: sampledAt,
                    usedPercent: usedPercent,
                    resetsAt: reset,
                    windowMinutes: windowMinutes))
                existingRecordKeys.insert(recordKey)
            }
        }

        guard !synthesized.isEmpty else { return existingDataset }
        self.records.append(contentsOf: synthesized)
        self.pruneOldRecords(now: now)
        self.records.sort { lhs, rhs in
            if lhs.sampledAt == rhs.sampledAt {
                if lhs.resetsAt == rhs.resetsAt {
                    return lhs.usedPercent < rhs.usedPercent
                }
                return lhs.resetsAt < rhs.resetsAt
            }
            return lhs.sampledAt < rhs.sampledAt
        }
        self.persist()
        return self.buildDataset(accountKey: accountKey)
    }

    private func shouldAccept(_ sample: HistoricalUsageRecord) -> Bool {
        guard let prior = self.records
            .last(where: {
                $0.provider == sample.provider &&
                    $0.windowKind == sample.windowKind &&
                    $0.accountKey == sample.accountKey &&
                    $0.windowMinutes == sample.windowMinutes
            })
        else {
            return true
        }

        if prior.resetsAt != sample.resetsAt { return true }
        if sample.sampledAt.timeIntervalSince(prior.sampledAt) >= Self.writeInterval { return true }
        if abs(sample.usedPercent - prior.usedPercent) >= Self.writeDeltaThreshold { return true }
        return false
    }

    private func pruneOldRecords(now: Date) {
        let cutoff = now.addingTimeInterval(-Self.retentionDays)
        self.records.removeAll { $0.sampledAt < cutoff }
    }

    private func ensureLoaded() {
        guard !self.loaded else { return }
        self.loaded = true
        self.records = self.readRecordsFromDisk()
        self.pruneOldRecords(now: .init())
    }

    private func readRecordsFromDisk() -> [HistoricalUsageRecord] {
        guard let data = try? Data(contentsOf: self.fileURL), !data.isEmpty else { return [] }
        guard let text = String(data: data, encoding: .utf8) else { return [] }

        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        var decoded: [HistoricalUsageRecord] = []
        decoded.reserveCapacity(text.count / 80)

        for rawLine in text.split(separator: "\n", omittingEmptySubsequences: true) {
            let line = String(rawLine).trimmingCharacters(in: .whitespacesAndNewlines)
            guard !line.isEmpty, let lineData = line.data(using: .utf8) else { continue }
            guard var record = try? decoder.decode(HistoricalUsageRecord.self, from: lineData) else { continue }
            record = HistoricalUsageRecord(
                v: record.v,
                provider: record.provider,
                windowKind: record.windowKind,
                source: record.source,
                accountKey: record.accountKey?.isEmpty == false ? record.accountKey : nil,
                sampledAt: record.sampledAt,
                usedPercent: Self.clamp(record.usedPercent, lower: 0, upper: 100),
                resetsAt: Self.normalizeReset(record.resetsAt),
                windowMinutes: record.windowMinutes)
            decoded.append(record)
        }
        return decoded
    }

    private func persist() {
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        encoder.outputFormatting = [.sortedKeys]

        var lines: [String] = []
        lines.reserveCapacity(self.records.count)
        for record in self.records {
            guard let data = try? encoder.encode(record),
                  let line = String(data: data, encoding: .utf8)
            else {
                continue
            }
            lines.append(line)
        }

        let payload = (lines.joined(separator: "\n") + "\n").data(using: .utf8) ?? Data()
        let directory = self.fileURL.deletingLastPathComponent()
        do {
            try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
            try payload.write(to: self.fileURL, options: [.atomic])
        } catch {
            // Best-effort cache file; ignore write failures.
        }
    }

    private func buildDataset(accountKey: String?) -> CodexHistoricalDataset? {
        let scoped = self.records.filter { record in
            guard Self.isCodexSecondaryRecord(record) else { return false }
            if let accountKey {
                return record.accountKey == accountKey
            }
            return record.accountKey == nil
        }
        return self.buildDataset(from: scoped)
    }

    private func buildDataset(
        canonicalAccountKey: String?,
        canonicalEmailHashKey: String?,
        legacyEmailHash: String?,
        hasAdjacentMultiAccountVeto: Bool) -> CodexHistoricalDataset?
    {
        guard let canonicalAccountKey else {
            return self.buildDataset(accountKey: nil)
        }

        let shouldIncludeUnscoped = CodexHistoryOwnership.hasStrictSingleAccountContinuity(
            scopedRawKeys: Self.scopedRawKeysRelevantToCodexUnscopedHistory(self.records),
            targetCanonicalKey: canonicalAccountKey,
            canonicalEmailHashKey: canonicalEmailHashKey,
            legacyEmailHash: legacyEmailHash,
            hasAdjacentMultiAccountVeto: hasAdjacentMultiAccountVeto)

        let scoped = self.records.filter { record in
            guard Self.isCodexSecondaryRecord(record) else { return false }
            guard let rawKey = record.accountKey else {
                return shouldIncludeUnscoped
            }

            let owner = CodexHistoryOwnership.classifyPersistedKey(rawKey, legacyEmailHash: legacyEmailHash)
            return CodexHistoryOwnership.belongsToTargetContinuity(
                owner,
                targetCanonicalKey: canonicalAccountKey,
                canonicalEmailHashKey: canonicalEmailHashKey)
        }
        return self.buildDataset(from: scoped)
    }

    private func buildDataset(from scoped: [HistoricalUsageRecord]) -> CodexHistoricalDataset? {
        struct WeekKey: Hashable {
            let resetsAt: Date
            let windowMinutes: Int
        }

        if scoped.isEmpty { return nil }

        let grouped = Dictionary(grouping: scoped) {
            WeekKey(resetsAt: $0.resetsAt, windowMinutes: $0.windowMinutes)
        }

        var weeks: [HistoricalWeekProfile] = []
        weeks.reserveCapacity(grouped.count)

        for (key, samples) in grouped {
            let duration = TimeInterval(key.windowMinutes) * 60
            guard duration > 0 else { continue }
            let windowStart = key.resetsAt.addingTimeInterval(-duration)
            guard Self.isCompleteWeek(samples: samples, windowStart: windowStart, resetsAt: key.resetsAt) else {
                continue
            }

            guard let curve = Self.reconstructWeekCurve(
                samples: samples,
                windowStart: windowStart,
                windowDuration: duration,
                gridPointCount: CodexHistoricalDataset.gridPointCount)
            else {
                continue
            }

            weeks.append(HistoricalWeekProfile(
                resetsAt: key.resetsAt,
                windowMinutes: key.windowMinutes,
                curve: curve))
        }

        weeks.sort { $0.resetsAt < $1.resetsAt }
        if weeks.isEmpty { return nil }
        return CodexHistoricalDataset(weeks: weeks)
    }

    private nonisolated static func isCodexSecondaryRecord(_ record: HistoricalUsageRecord) -> Bool {
        record.provider == .codex && record.windowKind == .secondary && record.windowMinutes > 0
    }

    private static func reconstructWeekCurve(
        samples: [HistoricalUsageRecord],
        windowStart: Date,
        windowDuration: TimeInterval,
        gridPointCount: Int) -> [Double]?
    {
        guard gridPointCount >= 2 else { return nil }

        var points = samples.map { sample -> (u: Double, value: Double) in
            let offset = sample.sampledAt.timeIntervalSince(windowStart)
            let u = Self.clamp(offset / windowDuration, lower: 0, upper: 1)
            return (u: u, value: Self.clamp(sample.usedPercent, lower: 0, upper: 100))
        }
        points.sort { lhs, rhs in
            if lhs.u == rhs.u {
                return lhs.value < rhs.value
            }
            return lhs.u < rhs.u
        }

        guard !points.isEmpty else { return nil }

        // Enforce monotonicity on observed samples before interpolation.
        var monotonePoints: [(u: Double, value: Double)] = []
        monotonePoints.reserveCapacity(points.count)
        var runningMax = 0.0
        for point in points {
            runningMax = max(runningMax, point.value)
            monotonePoints.append((u: point.u, value: runningMax))
        }

        // Anchor reconstructed curves to reset start and end-of-week plateau.
        let endValue = monotonePoints.last?.value ?? 0
        monotonePoints.append((u: 0, value: 0))
        monotonePoints.append((u: 1, value: endValue))
        monotonePoints.sort { lhs, rhs in
            if lhs.u == rhs.u {
                return lhs.value < rhs.value
            }
            return lhs.u < rhs.u
        }
        runningMax = 0
        for index in monotonePoints.indices {
            runningMax = max(runningMax, monotonePoints[index].value)
            monotonePoints[index].value = runningMax
        }

        var curve = Array(repeating: 0.0, count: gridPointCount)
        let first = monotonePoints[0]
        let last = monotonePoints[monotonePoints.count - 1]

        var upperIndex = 1
        let denominator = Double(gridPointCount - 1)

        for index in 0..<gridPointCount {
            let u = Double(index) / denominator
            if u <= first.u {
                curve[index] = first.value
                continue
            }
            if u >= last.u {
                curve[index] = last.value
                continue
            }

            while upperIndex < monotonePoints.count, monotonePoints[upperIndex].u < u {
                upperIndex += 1
            }

            let hi = monotonePoints[min(upperIndex, monotonePoints.count - 1)]
            let lo = monotonePoints[max(0, upperIndex - 1)]
            if hi.u <= lo.u {
                curve[index] = max(lo.value, hi.value)
                continue
            }

            let ratio = Self.clamp((u - lo.u) / (hi.u - lo.u), lower: 0, upper: 1)
            curve[index] = lo.value + (hi.value - lo.value) * ratio
        }

        // Re-enforce monotonicity on reconstructed grid.
        var curveMax = 0.0
        for index in curve.indices {
            curve[index] = Self.clamp(curve[index], lower: 0, upper: 100)
            curveMax = max(curveMax, curve[index])
            curve[index] = curveMax
        }
        return curve
    }

    private static func isCompleteWeek(samples: [HistoricalUsageRecord], windowStart: Date, resetsAt: Date) -> Bool {
        guard samples.count >= self.minimumWeekSamples else { return false }
        let startBoundary = windowStart.addingTimeInterval(Self.boundaryCoverageWindow)
        let endBoundary = resetsAt.addingTimeInterval(-Self.boundaryCoverageWindow)
        let hasStartCoverage = samples.contains { sample in
            sample.sampledAt >= windowStart && sample.sampledAt <= startBoundary
        }
        let hasEndCoverage = samples.contains { sample in
            sample.sampledAt >= endBoundary && sample.sampledAt <= resetsAt
        }
        return hasStartCoverage && hasEndCoverage
    }

    private nonisolated static func scopedRawKeysRelevantToCodexUnscopedHistory(
        _ records: [HistoricalUsageRecord]) -> [String]
    {
        let unscopedRecords = records.filter { record in
            Self.isCodexSecondaryRecord(record) && record.accountKey == nil
        }
        guard let continuityWindow = self.historicalContinuityWindow(for: unscopedRecords) else {
            return []
        }

        return records.compactMap { record in
            guard Self.isCodexSecondaryRecord(record),
                  let accountKey = record.accountKey,
                  continuityWindow.contains(record.sampledAt)
            else {
                return nil
            }
            return accountKey
        }
    }

    private nonisolated static func historicalContinuityWindow(
        for records: [HistoricalUsageRecord]) -> ClosedRange<Date>?
    {
        let sampledDates = records.map(\.sampledAt)
        guard let lowerBound = sampledDates.min(),
              let upperBound = sampledDates.max()
        else {
            return nil
        }
        let expansion = TimeInterval(records.map(\.windowMinutes).max() ?? 0) * 60
        return lowerBound.addingTimeInterval(-expansion)...upperBound.addingTimeInterval(expansion)
    }

    private struct DayUsage {
        let start: Date
        let end: Date
        let creditsUsed: Double
    }

    private static func parseDayUsages(
        from breakdown: [OpenAIDashboardDailyBreakdown],
        asOf: Date,
        fillingFrom expectedCoverageStart: Date? = nil) -> [DayUsage]
    {
        var creditsByStart: [Date: Double] = [:]
        creditsByStart.reserveCapacity(breakdown.count)

        for day in breakdown {
            guard let dayStart = Self.dayStart(for: day.day) else { continue }
            creditsByStart[dayStart, default: 0] += max(0, day.totalCreditsUsed)
        }

        let calendar = Self.gregorianCalendar()
        var dayUsages: [DayUsage] = []
        dayUsages.reserveCapacity(creditsByStart.count)
        for (dayStart, credits) in creditsByStart {
            guard let nominalEnd = calendar.date(byAdding: .day, value: 1, to: dayStart) else { continue }
            let effectiveEnd: Date = if dayStart <= asOf, asOf < nominalEnd {
                asOf
            } else {
                nominalEnd
            }
            guard effectiveEnd > dayStart else { continue }
            dayUsages.append(DayUsage(start: dayStart, end: effectiveEnd, creditsUsed: credits))
        }

        dayUsages.sort { lhs, rhs in lhs.start < rhs.start }
        return Self.fillMissingZeroUsageDays(
            in: dayUsages,
            through: asOf,
            fillingFrom: expectedCoverageStart)
    }

    private static func fillMissingZeroUsageDays(
        in dayUsages: [DayUsage],
        through asOf: Date,
        fillingFrom expectedCoverageStart: Date? = nil) -> [DayUsage]
    {
        guard let firstStart = dayUsages.first?.start else { return [] }

        let calendar = Self.gregorianCalendar()
        let fillStart: Date = if let expectedCoverageStart {
            min(firstStart, calendar.startOfDay(for: expectedCoverageStart))
        } else {
            firstStart
        }
        let finalDayStart = calendar.startOfDay(for: asOf)
        guard fillStart <= finalDayStart else { return dayUsages }

        let creditsByStart = Dictionary(uniqueKeysWithValues: dayUsages.map { ($0.start, $0.creditsUsed) })
        let daySpan = max(0, calendar.dateComponents([.day], from: fillStart, to: finalDayStart).day ?? 0)
        var filled: [DayUsage] = []
        filled.reserveCapacity(daySpan + 1)

        var cursor = fillStart
        while cursor <= finalDayStart {
            guard let nominalEnd = calendar.date(byAdding: .day, value: 1, to: cursor) else { break }
            let effectiveEnd: Date = if cursor <= asOf, asOf < nominalEnd {
                asOf
            } else {
                nominalEnd
            }
            guard effectiveEnd > cursor else { break }
            filled.append(DayUsage(
                start: cursor,
                end: effectiveEnd,
                creditsUsed: creditsByStart[cursor] ?? 0))
            guard let next = calendar.date(byAdding: .day, value: 1, to: cursor) else { break }
            cursor = next
        }

        return filled
    }

    private static func dayStart(for key: String) -> Date? {
        let components = key.split(separator: "-", omittingEmptySubsequences: true)
        guard components.count == 3,
              let year = Int(components[0]),
              let month = Int(components[1]),
              let day = Int(components[2])
        else {
            return nil
        }

        let calendar = Self.gregorianCalendar()
        var dateComponents = DateComponents()
        dateComponents.calendar = calendar
        dateComponents.timeZone = calendar.timeZone
        dateComponents.year = year
        dateComponents.month = month
        dateComponents.day = day
        dateComponents.hour = 0
        dateComponents.minute = 0
        dateComponents.second = 0
        return dateComponents.date
    }

    private static func creditsUsed(from dayUsages: [DayUsage], between start: Date, and end: Date) -> Double {
        guard end > start else { return 0 }
        var total = 0.0
        for day in dayUsages {
            if day.end <= start { continue }
            if day.start >= end { break }
            let overlapStart = max(day.start, start)
            let overlapEnd = min(day.end, end)
            guard overlapEnd > overlapStart else { continue }

            let dayDuration = day.end.timeIntervalSince(day.start)
            guard dayDuration > 0 else { continue }
            let overlap = overlapEnd.timeIntervalSince(overlapStart)
            total += day.creditsUsed * (overlap / dayDuration)
        }
        return max(0, total)
    }

    nonisolated static func defaultFileURL() -> URL {
        let root = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first
            ?? FileManager.default.homeDirectoryForCurrentUser
        return root
            .appendingPathComponent("CodexBar", isDirectory: true)
            .appendingPathComponent("usage-history.jsonl", isDirectory: false)
    }

    private nonisolated static func clamp(_ value: Double, lower: Double, upper: Double) -> Double {
        min(upper, max(lower, value))
    }

    private nonisolated static func clampDate(_ value: Date, lower: Date, upper: Date) -> Date {
        min(upper, max(lower, value))
    }

    private nonisolated static func normalizeReset(_ value: Date) -> Date {
        let bucket = Self.resetBucketSeconds
        guard bucket > 0 else { return value }
        let rounded = (value.timeIntervalSinceReferenceDate / bucket).rounded() * bucket
        return Date(timeIntervalSinceReferenceDate: rounded)
    }

    private nonisolated static func gregorianCalendar() -> Calendar {
        var calendar = Calendar(identifier: .gregorian)
        calendar.timeZone = TimeZone.current
        return calendar
    }

    #if DEBUG
    nonisolated static func _dayStartForTesting(_ key: String) -> Date? {
        self.dayStart(for: key)
    }

    nonisolated static func _creditsUsedForTesting(
        breakdown: [OpenAIDashboardDailyBreakdown],
        asOf: Date,
        start: Date,
        end: Date) -> Double
    {
        let dayUsages = Self.parseDayUsages(from: breakdown, asOf: asOf)
        return Self.creditsUsed(from: dayUsages, between: start, and: end)
    }
    #endif
}

enum CodexHistoricalPaceEvaluator {
    static let minimumCompleteWeeksForHistorical = 3
    static let minimumWeeksForRisk = 5
    private static let recencyTauWeeks: Double = 3
    private static let epsilon: Double = 1e-9
    private static let resetBucketSeconds: TimeInterval = 5 * 60

    static func evaluate(window: RateWindow, now: Date, dataset: CodexHistoricalDataset?) -> UsagePace? {
        guard let dataset else { return nil }
        guard let resetsAt = window.resetsAt else { return nil }
        let minutes = window.windowMinutes ?? 10080
        guard minutes > 0 else { return nil }

        let duration = TimeInterval(minutes) * 60
        guard duration > 0 else { return nil }

        let timeUntilReset = resetsAt.timeIntervalSince(now)
        guard timeUntilReset > 0, timeUntilReset <= duration else { return nil }
        let normalizedResetsAt = Self.normalizeReset(resetsAt)

        let elapsed = Self.clamp(duration - timeUntilReset, lower: 0, upper: duration)
        let actual = Self.clamp(window.usedPercent, lower: 0, upper: 100)
        if elapsed == 0, actual > 0 { return nil }

        let uNow = Self.clamp(elapsed / duration, lower: 0, upper: 1)
        let scopedWeeks = dataset.weeks.filter { week in
            week.windowMinutes == minutes && week.resetsAt < normalizedResetsAt
        }
        guard scopedWeeks.count >= Self.minimumCompleteWeeksForHistorical else { return nil }

        let weightedWeeks = scopedWeeks.map { week in
            let ageWeeks = Self.clamp(
                normalizedResetsAt.timeIntervalSince(week.resetsAt) / duration,
                lower: 0,
                upper: Double.greatestFiniteMagnitude)
            let weight = exp(-ageWeeks / Self.recencyTauWeeks)
            return (week: week, weight: weight)
        }
        let totalWeight = weightedWeeks.reduce(0.0) { $0 + $1.weight }
        guard totalWeight > Self.epsilon else { return nil }

        let totalWeightSquared = weightedWeeks.reduce(0.0) { $0 + ($1.weight * $1.weight) }
        let nEff = totalWeightSquared > Self.epsilon ? (totalWeight * totalWeight) / totalWeightSquared : 0
        let lambda = Self.clamp((nEff - 2) / 6, lower: 0, upper: 1)

        let gridCount = CodexHistoricalDataset.gridPointCount
        let denominator = Double(gridCount - 1)
        var expectedCurve = Array(repeating: 0.0, count: gridCount)
        for index in 0..<gridCount {
            let u = Double(index) / denominator
            let values = weightedWeeks.map { $0.week.curve[index] }
            let weights = weightedWeeks.map(\.weight)
            let historicalMedian = Self.weightedMedian(values: values, weights: weights)
            let linearBaseline = 100 * u
            // Historical demand can exceed a sustainable quota pace. Never call that excess a reserve.
            expectedCurve[index] = Self.clamp(
                (lambda * historicalMedian) + ((1 - lambda) * linearBaseline),
                lower: 0,
                upper: linearBaseline)
        }

        // Expected cumulative usage should be monotone.
        var runningExpected = 0.0
        for index in expectedCurve.indices {
            runningExpected = max(runningExpected, expectedCurve[index])
            expectedCurve[index] = runningExpected
        }

        let expectedNow = Self.interpolate(curve: expectedCurve, at: uNow)

        var weightedRunOutMass = 0.0
        var crossingCandidates: [(etaSeconds: TimeInterval, weight: Double)] = []
        crossingCandidates.reserveCapacity(weightedWeeks.count)

        for weighted in weightedWeeks {
            var extendedCurve = weighted.week.curve
            if let capIndex = extendedCurve.firstIndex(where: { $0 >= 100 - Self.epsilon }),
               capIndex > 0, capIndex < extendedCurve.count - 1
            {
                let gridCount = CodexHistoricalDataset.gridPointCount
                let uCap = Double(capIndex) / Double(gridCount - 1)
                let valCap = extendedCurve[capIndex]
                let slope: Double = valCap / uCap
                for i in capIndex..<extendedCurve.count {
                    let u = Double(i) / Double(gridCount - 1)
                    extendedCurve[i] = slope * u
                }
            }

            let weight = weighted.weight
            let weekNow = Self.interpolate(curve: extendedCurve, at: uNow)
            let shift = actual - weekNow
            let shiftedEnd = (extendedCurve.last ?? 0) + shift
            let runOut = shiftedEnd >= 100 - Self.epsilon
            if runOut {
                weightedRunOutMass += weight
                if let crossingU = Self.firstCrossing(
                    after: uNow,
                    curve: extendedCurve,
                    shift: shift,
                    actualAtNow: actual)
                {
                    let etaSeconds = max(0, (crossingU - uNow) * duration)
                    crossingCandidates.append((etaSeconds: etaSeconds, weight: weight))
                }
            }
        }

        let smoothedProbability = Self.clamp(
            (weightedRunOutMass + 0.5) / (totalWeight + 1),
            lower: 0,
            upper: 1)
        var runOutProbability: Double? = scopedWeeks.count >= Self.minimumWeeksForRisk ? smoothedProbability : nil

        var willLastToReset = smoothedProbability < 0.5
        var etaSeconds: TimeInterval?

        if actual >= 100 {
            willLastToReset = false
            etaSeconds = 0
            runOutProbability = 1
        } else if !willLastToReset {
            let values = crossingCandidates.map(\.etaSeconds)
            let weights = crossingCandidates.map(\.weight)
            if values.isEmpty {
                willLastToReset = true
            } else {
                etaSeconds = max(0, Self.weightedMedian(values: values, weights: weights))
            }
        }

        return UsagePace.historical(
            expectedUsedPercent: expectedNow,
            actualUsedPercent: actual,
            etaSeconds: etaSeconds,
            willLastToReset: willLastToReset,
            runOutProbability: runOutProbability,
            projectedRemainingUsage: max(0, (expectedCurve.last ?? expectedNow) - expectedNow))
    }

    private static func firstCrossing(
        after uNow: Double,
        curve: [Double],
        shift: Double,
        actualAtNow: Double) -> Double?
    {
        let gridCount = curve.count
        guard gridCount >= 2 else { return nil }

        let denominator = Double(gridCount - 1)
        var previousU = uNow
        var previousValue = actualAtNow

        let startIndex = min(gridCount - 1, max(1, Int(floor(uNow * denominator)) + 1))
        for index in startIndex..<gridCount {
            let u = Double(index) / denominator
            if u <= uNow + Self.epsilon { continue }
            let value = Self.clamp(curve[index] + shift, lower: 0, upper: 100)
            if previousValue < 100 - Self.epsilon, value >= 100 - Self.epsilon {
                let delta = value - previousValue
                if abs(delta) <= Self.epsilon { return u }
                let ratio = Self.clamp((100 - previousValue) / delta, lower: 0, upper: 1)
                return Self.clamp(previousU + ratio * (u - previousU), lower: uNow, upper: 1)
            }
            previousU = u
            previousValue = value
        }
        return nil
    }

    private static func interpolate(curve: [Double], at u: Double) -> Double {
        guard !curve.isEmpty else { return 0 }
        if curve.count == 1 { return curve[0] }

        let clipped = Self.clamp(u, lower: 0, upper: 1)
        let scaled = clipped * Double(curve.count - 1)
        let lower = Int(floor(scaled))
        let upper = min(curve.count - 1, lower + 1)
        if lower == upper { return curve[lower] }
        let ratio = scaled - Double(lower)
        return curve[lower] + ((curve[upper] - curve[lower]) * ratio)
    }

    private static func weightedMedian(values: [Double], weights: [Double]) -> Double {
        guard values.count == weights.count, !values.isEmpty else { return 0 }
        let pairs = zip(values, weights)
            .map { (value: $0, weight: max(0, $1)) }
            .sorted { lhs, rhs in lhs.value < rhs.value }
        let totalWeight = pairs.reduce(0.0) { $0 + $1.weight }
        if totalWeight <= Self.epsilon {
            let sortedValues = values.sorted()
            return sortedValues[sortedValues.count / 2]
        }

        let threshold = totalWeight / 2
        var cumulative = 0.0
        for pair in pairs {
            cumulative += pair.weight
            if cumulative >= threshold {
                return pair.value
            }
        }
        return pairs.last?.value ?? 0
    }

    private static func clamp(_ value: Double, lower: Double, upper: Double) -> Double {
        min(upper, max(lower, value))
    }

    private static func normalizeReset(_ value: Date) -> Date {
        let bucket = Self.resetBucketSeconds
        guard bucket > 0 else { return value }
        let rounded = (value.timeIntervalSinceReferenceDate / bucket).rounded() * bucket
        return Date(timeIntervalSinceReferenceDate: rounded)
    }
}
