//
//  UsageAnalyticsView.swift
//  Confab
//
//  Usage analytics: tokens / questions / money, over time and by model
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
//
// This file is part of Confab.
//
// Confab is licensed under the PolyForm Noncommercial License 1.0.0.
// You may use, study, modify, and share it for any noncommercial
// purpose. Commercial use — including selling Confab or any part of
// it, standalone or bundled into another product or service —
// requires a separate commercial license from the copyright holder.
//
// See the LICENSE file or
// <https://polyformproject.org/licenses/noncommercial/1.0.0> for
// the full license text. For commercial licensing, contact Rune
// Olsen via <https://confab.no>.


import SwiftUI
import Charts

private enum AnalyticsMetric: String, CaseIterable, Identifiable {
    case tokens
    case questions
    case cost

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .tokens: return "number"
        case .questions: return "bubble.left.and.bubble.right"
        case .cost: return "dollarsign.circle"
        }
    }

    var color: Color {
        switch self {
        case .tokens: return .confabAccent
        case .questions: return .confabSuccess
        case .cost: return .confabWarning
        }
    }
}

private enum AnalyticsChartMode: String, CaseIterable, Identifiable {
    case overTime
    case byModel
    case byProvider

    var id: String { rawValue }
}

struct UsageAnalyticsView: View {
    @Environment(\.dismiss) var dismiss

    @State private var timeframe: AnalyticsTimeframe = .last7Days
    @State private var metric: AnalyticsMetric = .tokens
    @State private var chartMode: AnalyticsChartMode = .overTime

    @State private var overallStats = UsageStats()
    @State private var modelStats: [ModelUsageStat] = []
    @State private var providerStats: [ProviderUsageStat] = []
    @State private var dailyStats: [DailyUsageStat] = []

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                timeframePicker

                Divider()

                ScrollView {
                    VStack(alignment: .leading, spacing: 20) {
                        summaryTiles

                        VStack(alignment: .leading, spacing: 12) {
                            chartModePicker
                            chartSection
                        }

                        if chartMode == .byModel && !modelStats.isEmpty {
                            modelBreakdownList
                        }

                        if chartMode == .byProvider && !providerStats.isEmpty {
                            providerBreakdownList
                        }
                    }
                    .padding(20)
                }
            }
            .navigationTitle("Analytics")
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { dismiss() }
                }
            }
            .frame(minWidth: 700, idealWidth: 780, minHeight: 620, idealHeight: 680)
        }
        .task(id: timeframe) {
            loadStats()
        }
    }

    // MARK: - Timeframe

    private var timeframePicker: some View {
        Picker("", selection: $timeframe) {
            Text("Today").tag(AnalyticsTimeframe.today)
            Text("7 Days").tag(AnalyticsTimeframe.last7Days)
            Text("Week").tag(AnalyticsTimeframe.week)
            Text("Month").tag(AnalyticsTimeframe.month)
            Text("Year").tag(AnalyticsTimeframe.year)
            Text("Total").tag(AnalyticsTimeframe.total)
        }
        .pickerStyle(.segmented)
        .labelsHidden()
        .padding(.horizontal, 20)
        .padding(.top, 12)
        .padding(.bottom, 12)
    }

    // MARK: - Summary Tiles

    private var summaryTiles: some View {
        HStack(spacing: 12) {
            MetricTile(
                title: "Tokens",
                value: overallStats.totalTokensDisplay,
                icon: AnalyticsMetric.tokens.icon,
                color: AnalyticsMetric.tokens.color,
                isSelected: metric == .tokens
            ) { metric = .tokens }

            MetricTile(
                title: "Questions",
                value: "\(overallStats.totalQuestions)",
                icon: AnalyticsMetric.questions.icon,
                color: AnalyticsMetric.questions.color,
                isSelected: metric == .questions
            ) { metric = .questions }

            MetricTile(
                title: "Money Used",
                value: overallStats.totalCostDisplay,
                icon: AnalyticsMetric.cost.icon,
                color: AnalyticsMetric.cost.color,
                isSelected: metric == .cost
            ) { metric = .cost }
        }
    }

    // MARK: - Chart

    private var chartModePicker: some View {
        Picker("", selection: $chartMode) {
            Text("Over Time").tag(AnalyticsChartMode.overTime)
            Text("By Model").tag(AnalyticsChartMode.byModel)
            Text("By Provider").tag(AnalyticsChartMode.byProvider)
        }
        .pickerStyle(.segmented)
        .labelsHidden()
        .frame(maxWidth: 400)
    }

    @ViewBuilder
    private var chartSection: some View {
        switch chartMode {
        case .overTime:
            timeSeriesChart
        case .byModel:
            byModelChart
        case .byProvider:
            byProviderChart
        }
    }

    private var timeSeriesChart: some View {
        Group {
            if dailyStats.isEmpty {
                emptyChartPlaceholder
            } else {
                Chart(dailyStats) { stat in
                    BarMark(
                        x: .value("Day", stat.day, unit: .day),
                        y: .value("Value", dailyValue(for: stat))
                    )
                    .foregroundStyle(metric.color)
                }
                .frame(height: 220)
            }
        }
    }

    private var byModelChart: some View {
        Group {
            if modelStats.isEmpty {
                emptyChartPlaceholder
            } else {
                Chart(modelStats) { stat in
                    SectorMark(
                        angle: .value("Value", modelValue(for: stat)),
                        innerRadius: .ratio(0.55),
                        angularInset: 1.5
                    )
                    .foregroundStyle(by: .value("Model", stat.modelId))
                    .cornerRadius(4)
                }
                .frame(height: 240)
                .chartLegend(position: .bottom, alignment: .center, spacing: 8)
            }
        }
    }

    private var byProviderChart: some View {
        Group {
            if providerStats.isEmpty {
                emptyChartPlaceholder
            } else {
                Chart(providerStats) { stat in
                    SectorMark(
                        angle: .value("Value", providerValue(for: stat)),
                        innerRadius: .ratio(0.55),
                        angularInset: 1.5
                    )
                    .foregroundStyle(by: .value("Provider", providerDisplayName(stat.provider)))
                    .cornerRadius(4)
                }
                .frame(height: 240)
                .chartLegend(position: .bottom, alignment: .center, spacing: 8)
            }
        }
    }

    private var emptyChartPlaceholder: some View {
        VStack(spacing: 8) {
            Image(systemName: "chart.bar.xaxis")
                .font(.system(size: 32))
                .foregroundColor(.secondary)
            Text("No usage data for this timeframe")
                .font(.callout)
                .foregroundColor(.secondary)
        }
        .frame(maxWidth: .infinity)
        .frame(height: 220)
    }

    // MARK: - By Model List

    private var modelBreakdownList: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("By Model")
                .font(.headline)
                .padding(.bottom, 4)

            ForEach(modelStats) { stat in
                HStack {
                    Text(stat.modelId)
                        .font(.body)
                        .lineLimit(1)
                    Spacer()
                    Text(modelValueDisplay(for: stat))
                        .font(.body.monospacedDigit())
                        .foregroundColor(.secondary)
                }
                .padding(.vertical, 4)

                if stat.id != modelStats.last?.id {
                    Divider()
                }
            }
        }
        .padding(16)
        .background(Color.confabSurface.opacity(0.5))
        .cornerRadius(10)
    }

    // MARK: - By Provider List

    private var providerBreakdownList: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("By Provider")
                .font(.headline)
                .padding(.bottom, 4)

            ForEach(providerStats) { stat in
                HStack {
                    Text(providerDisplayName(stat.provider))
                        .font(.body)
                        .lineLimit(1)
                    Spacer()
                    Text(providerValueDisplay(for: stat))
                        .font(.body.monospacedDigit())
                        .foregroundColor(.secondary)
                }
                .padding(.vertical, 4)

                if stat.id != providerStats.last?.id {
                    Divider()
                }
            }
        }
        .padding(16)
        .background(Color.confabSurface.opacity(0.5))
        .cornerRadius(10)
    }

    private func providerDisplayName(_ rawProvider: String) -> String {
        Settings.Provider(rawValue: rawProvider)?.displayName ?? rawProvider
    }

    // MARK: - Value helpers

    private func dailyValue(for stat: DailyUsageStat) -> Double {
        switch metric {
        case .tokens: return Double(stat.totalTokens)
        case .questions: return Double(stat.questionCount)
        case .cost: return stat.totalCost
        }
    }

    private func modelValue(for stat: ModelUsageStat) -> Double {
        switch metric {
        case .tokens: return Double(stat.totalTokens)
        case .questions: return Double(stat.questionCount)
        case .cost: return stat.totalCost
        }
    }

    private func modelValueDisplay(for stat: ModelUsageStat) -> String {
        switch metric {
        case .tokens: return stat.totalTokensDisplay
        case .questions: return "\(stat.questionCount)"
        case .cost: return stat.totalCostDisplay
        }
    }

    private func providerValue(for stat: ProviderUsageStat) -> Double {
        switch metric {
        case .tokens: return Double(stat.totalTokens)
        case .questions: return Double(stat.questionCount)
        case .cost: return stat.totalCost
        }
    }

    private func providerValueDisplay(for stat: ProviderUsageStat) -> String {
        switch metric {
        case .tokens: return stat.totalTokensDisplay
        case .questions: return "\(stat.questionCount)"
        case .cost: return stat.totalCostDisplay
        }
    }

    // MARK: - Data Loading

    /// Sourced from `usage_events`, not `messages` — reflects usage for every completed
    /// generation regardless of whether the conversation it belongs to was ever saved.
    private func loadStats() {
        let range = timeframe.dateRange()
        overallStats = (try? DatabaseService.shared.getUsageEventTotals(from: range.start, to: range.end)) ?? UsageStats()
        modelStats = (try? DatabaseService.shared.getUsageEventsByModel(from: range.start, to: range.end)) ?? []
        providerStats = (try? DatabaseService.shared.getUsageEventsByProvider(from: range.start, to: range.end)) ?? []

        let dailyFrom = range.start ?? overallStats.firstMessageDate ?? range.end
        dailyStats = (try? DatabaseService.shared.getDailyUsageEvents(from: dailyFrom, to: range.end)) ?? []
    }
}

// MARK: - Metric Tile

private struct MetricTile: View {
    let title: LocalizedStringKey
    let value: String
    let icon: String
    let color: Color
    let isSelected: Bool
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            VStack(alignment: .leading, spacing: 8) {
                HStack {
                    Image(systemName: icon)
                        .foregroundColor(color)
                    Spacer()
                }
                Text(value)
                    .font(.title2.monospacedDigit())
                    .fontWeight(.bold)
                    .foregroundColor(.primary)
                    .lineLimit(1)
                    .minimumScaleFactor(0.6)
                Text(title)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            .padding(14)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(isSelected ? color.opacity(0.15) : Color.confabSurface.opacity(0.5))
            .overlay(
                RoundedRectangle(cornerRadius: 10)
                    .stroke(isSelected ? color : Color.clear, lineWidth: 1.5)
            )
            .cornerRadius(10)
        }
        .buttonStyle(.plain)
    }
}

#Preview {
    UsageAnalyticsView()
}
