import Foundation

public enum Provider: String, CaseIterable, Codable, Hashable, Sendable {
    case claude = "Claude"
    case codex = "Codex"
    case gemini = "Gemini"
    case hermes = "Hermes"
    case opencode = "OpenCode"
}

public struct UsageRecord: Identifiable, Hashable, Sendable {
    public let id: UUID
    public let provider: Provider
    public let source: String
    public let sourcePath: String
    public let timestamp: Date
    public let sessionID: String
    public let model: String
    public let inputTokens: Int
    public let outputTokens: Int
    public let cachedTokens: Int
    public let reasoningTokens: Int
    public let toolTokens: Int
    public let totalTokens: Int

    public init(
        id: UUID = UUID(),
        provider: Provider,
        source: String,
        sourcePath: String,
        timestamp: Date,
        sessionID: String,
        model: String,
        inputTokens: Int,
        outputTokens: Int,
        cachedTokens: Int,
        reasoningTokens: Int,
        toolTokens: Int,
        explicitTotal: Int? = nil
    ) {
        self.id = id
        self.provider = provider
        self.source = source
        self.sourcePath = sourcePath
        self.timestamp = timestamp
        self.sessionID = sessionID
        self.model = model
        self.inputTokens = inputTokens
        self.outputTokens = outputTokens
        self.cachedTokens = cachedTokens
        self.reasoningTokens = reasoningTokens
        self.toolTokens = toolTokens
        self.totalTokens = explicitTotal ?? inputTokens + outputTokens + cachedTokens + reasoningTokens + toolTokens
    }
}

public struct TokenBucket: Hashable, Sendable {
    public let provider: Provider?
    public var inputTokens: Int = 0
    public var outputTokens: Int = 0
    public var cachedTokens: Int = 0
    public var reasoningTokens: Int = 0
    public var toolTokens: Int = 0
    public var totalTokens: Int = 0
    public var count: Int = 0

    public init(provider: Provider? = nil) {
        self.provider = provider
    }

    public mutating func add(_ record: UsageRecord) {
        add(
            inputTokens: record.inputTokens,
            outputTokens: record.outputTokens,
            cachedTokens: record.cachedTokens,
            reasoningTokens: record.reasoningTokens,
            toolTokens: record.toolTokens,
            totalTokens: record.totalTokens
        )
    }

    public mutating func add(
        inputTokens: Int,
        outputTokens: Int,
        cachedTokens: Int,
        reasoningTokens: Int,
        toolTokens: Int,
        totalTokens: Int
    ) {
        self.inputTokens += inputTokens
        self.outputTokens += outputTokens
        self.cachedTokens += cachedTokens
        self.reasoningTokens += reasoningTokens
        self.toolTokens += toolTokens
        self.totalTokens += totalTokens
        count += 1
    }
}

public struct SummaryCards: Hashable, Sendable {
    public let todayTokens: Int
    public let monthTokens: Int
    public let totalTokens: Int
    public let cacheHitRate: Int
    public let sessionCount: Int
}

public struct DailyPoint: Identifiable, Hashable, Sendable {
    public let id = UUID()
    public let date: Date
    public let values: [Provider: Int]
}

public enum TrendMode: String, CaseIterable, Sendable {
    case daily = "每日"
    case weekly = "每周"
    case monthly = "每月"
    case yearly = "每年"
}

public struct ToolRow: Identifiable, Hashable, Sendable {
    public let id = UUID()
    public let provider: Provider
    public let inputTokens: Int
    public let outputTokens: Int
    public let cachedTokens: Int
    public let totalTokens: Int
    public let trendTokens: [Int]
}

public struct DailyUsageDetail: Identifiable, Hashable, Sendable {
    public var id: Date { date }

    public let date: Date
    public var inputTokens: Int
    public var outputTokens: Int
    public var cachedTokens: Int
    public var totalTokens: Int
    public var providerTotals: [Provider: Int]

    public init(
        date: Date,
        inputTokens: Int = 0,
        outputTokens: Int = 0,
        cachedTokens: Int = 0,
        totalTokens: Int = 0,
        providerTotals: [Provider: Int] = [:]
    ) {
        self.date = date
        self.inputTokens = inputTokens
        self.outputTokens = outputTokens
        self.cachedTokens = cachedTokens
        self.totalTokens = totalTokens
        self.providerTotals = providerTotals
    }

    public mutating func add(_ record: UsageRecord) {
        add(
            provider: record.provider,
            inputTokens: record.inputTokens,
            outputTokens: record.outputTokens,
            cachedTokens: record.cachedTokens,
            totalTokens: record.totalTokens
        )
    }

    public mutating func add(
        provider: Provider,
        inputTokens: Int,
        outputTokens: Int,
        cachedTokens: Int,
        totalTokens: Int
    ) {
        self.inputTokens += inputTokens
        self.outputTokens += outputTokens
        self.cachedTokens += cachedTokens
        self.totalTokens += totalTokens
        providerTotals[provider, default: 0] += totalTokens
    }
}

public struct Insight: Identifiable, Hashable, Sendable {
    public enum Tone: String, Sendable {
        case warning
        case positive
        case accent
    }

    public let id = UUID()
    public let tone: Tone
    public let title: String
    public let message: String
}

public struct UsageSummary: Sendable {
    public let generatedAt: Date
    public let records: [UsageRecord]
    public let cards: SummaryCards
    public let providerTotals: [Provider: TokenBucket]
    public let todayProviderTotals: [Provider: TokenBucket]
    public let dailyTrend: [DailyPoint]
    public let trendPointsByMode: [TrendMode: [DailyPoint]]
    public let dailyDetails: [DailyUsageDetail]
    public let toolRows: [ToolRow]
    public let insights: [Insight]
}
