import SwiftUI

private let trendChartHeight: CGFloat = 90

// Cached formatters and a calendar to avoid allocating fresh ones on every
// SwiftUI body re-eval. Hover scrubbing on the trend bars triggers many
// re-evals per second; a fresh DateFormatter / Calendar each time was a
// measurable hot spot.
private let yyyymmdd: DateFormatter = {
    let f = DateFormatter()
    f.dateFormat = "yyyy-MM-dd"
    f.locale = Locale(identifier: "en_US_POSIX")
    f.timeZone = .current
    return f
}()

private let prettyDayFormat: DateFormatter = {
    let f = DateFormatter()
    f.dateFormat = "EEE MMM d"
    f.locale = Locale(identifier: "en_US_POSIX")
    return f
}()

private let mmmDayFormat: DateFormatter = {
    let f = DateFormatter()
    f.dateFormat = "MMM d"
    f.locale = Locale(identifier: "en_US_POSIX")
    f.timeZone = .current
    return f
}()

private let gregorianCalendar: Calendar = {
    var c = Calendar(identifier: .gregorian)
    c.timeZone = .current
    return c
}()

/// Switchable insight visualizations: trend, calendar, forecast, pulse, stats,
/// optimize, plus provider-specific plan views.
struct HeatmapSection: View {
    @Environment(AppStore.self) private var store

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            InsightPillSwitcher(selected: bindingMode, visibleModes: visibleModes)
            content
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .onAppear { ensureValidSelection() }
        .onChange(of: store.selectedProvider) { _, _ in ensureValidSelection() }
    }

    private var bindingMode: Binding<InsightMode> {
        Binding(get: { store.selectedInsight }, set: { store.selectedInsight = $0 })
    }

    private var visibleModes: [InsightMode] {
        // Plan sources from a provider's OAuth usage endpoint. Currently
        // implemented for Claude (Anthropic) and Codex (ChatGPT). Hidden on
        // All / Cursor / Droid / Gemini / Copilot until those providers ship
        // their own quota data sources.
        InsightMode.allCases.filter { mode in
            if mode == .plan {
                return store.selectedProvider == .claude || store.selectedProvider == .codex
            }
            return true
        }
    }

    private func ensureValidSelection() {
        if !visibleModes.contains(store.selectedInsight) {
            store.selectedInsight = visibleModes.first ?? .trend
        }
    }

    @ViewBuilder
    private var content: some View {
        switch store.selectedInsight {
        case .plan:
            if store.selectedProvider == .codex {
                CodexPlanInsight()
            } else {
                PlanInsight(usage: store.subscription)
            }
        case .trend: TrendInsight(days: store.payload.history.daily, period: store.trendPeriod)
        case .calendar: ContributionHeatmapInsight(days: store.payload.history.daily)
        case .forecast: ForecastInsight(days: store.payload.history.daily)
        case .pulse: PulseInsight(payload: store.payload)
        case .stats: StatsInsight(payload: store.payload)
        case .optimize: OptimizeInsight(payload: store.payload)
        }
    }
}

// MARK: - Pill Switcher

private struct InsightPillSwitcher: View {
    @Binding var selected: InsightMode
    let visibleModes: [InsightMode]

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 4) {
                ForEach(visibleModes) { mode in
                    Button {
                        selected = mode
                    } label: {
                        Text(mode.rawValue)
                            .font(.system(size: 11, weight: .medium))
                            .fixedSize()
                            .foregroundStyle(selected == mode ? AnyShapeStyle(.white) : AnyShapeStyle(.secondary))
                            .padding(.horizontal, 10)
                            .padding(.vertical, 4)
                            .background(
                                RoundedRectangle(cornerRadius: 6)
                                    .fill(selected == mode ? AnyShapeStyle(Theme.brandAccent) : AnyShapeStyle(Color.secondary.opacity(0.10)))
                            )
                    }
                    .buttonStyle(.plain)
                }
            }
        }
    }
}

// MARK: - Trend (14-day bar chart with peak + average)

private struct TrendInsight: View {
    let days: [DailyHistoryEntry]
    let period: Period

    private var trendDayCount: Int {
        switch period {
        case .today, .sevenDays: return 19
        case .thirtyDays: return 30
        case .month: return 31
        case .all: return min(days.count, 90)
        }
    }

    private var barGap: CGFloat {
        trendDayCount > 45 ? 2 : 4
    }

    var body: some View {
        let dayCount = trendDayCount
        let bars = buildTrendBars(from: days, dayCount: dayCount)
        let stats = computeTrendStats(bars: bars, allDays: days, dayCount: dayCount)
        // Tokens are real for the .all-providers view; per-provider history doesn't carry
        // token breakdown yet, so fall back to $ when no tokens are present.
        let totalTokens = bars.reduce(0.0) { $0 + $1.tokens }
        let useTokens = totalTokens > 0
        let metric: (TrendBar) -> Double = useTokens ? { $0.tokens } : { $0.cost }
        let maxValue = max(bars.map(metric).max() ?? 1, 0.01)
        let avgValue = bars.isEmpty ? 0 : bars.map(metric).reduce(0, +) / Double(bars.count)
        let peakValue = bars.filter({ metric($0) > 0 }).max(by: { metric($0) < metric($1) })
        let yesterdayValue = stats.yesterdayBar.map(metric)

        VStack(alignment: .leading, spacing: 10) {
            HStack(alignment: .firstTextBaseline) {
                VStack(alignment: .leading, spacing: 1) {
                    Text("Last \(dayCount) days")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Text(formatHero(useTokens: useTokens, tokens: totalTokens, dollars: stats.totalThisWindow))
                        .font(.system(size: 18, weight: .semibold, design: .rounded))
                        .monospacedDigit()
                        .foregroundStyle(.primary)
                }
                Spacer()
                if let delta = stats.deltaPercent {
                    HStack(spacing: 3) {
                        Image(systemName: delta >= 0 ? "arrow.up.right" : "arrow.down.right")
                            .font(.system(size: 9, weight: .bold))
                        Text("\(delta >= 0 ? "+" : "")\(String(format: "%.0f", delta))% vs prior \(dayCount)d")
                            .font(.system(size: 10.5))
                            .monospacedDigit()
                    }
                    .foregroundStyle(Theme.brandAccent)
                }
            }

            TrendChart(
                bars: bars,
                maxValue: maxValue,
                avgValue: avgValue,
                metric: metric,
                formatValue: { formatValue($0, useTokens: useTokens) },
                barGap: barGap
            )
            .zIndex(1)

            HStack(spacing: 14) {
                MiniStat(label: "Avg/day", value: formatValue(avgValue, useTokens: useTokens))
                MiniStat(label: "Peak", value: peakLabel(peakValue, metric: metric, useTokens: useTokens))
                MiniStat(label: "Yesterday", value: yesterdayValue.map { formatValue($0, useTokens: useTokens) } ?? "—")
            }
        }
    }

    private func formatHero(useTokens: Bool, tokens: Double, dollars: Double) -> String {
        useTokens ? "\(formatTokens(tokens)) tokens" : dollars.asCurrency()
    }

    private func formatValue(_ v: Double, useTokens: Bool) -> String {
        useTokens ? "\(formatTokens(v)) tok" : v.asCompactCurrency()
    }

    private func peakLabel(_ peak: TrendBar?, metric: (TrendBar) -> Double, useTokens: Bool) -> String {
        guard let peak, metric(peak) > 0 else { return "—" }
        return "\(formatValue(metric(peak), useTokens: useTokens)) on \(shortDate(peak.date))"
    }

    private func formatTokens(_ n: Double) -> String {
        if n >= 1_000_000 { return String(format: "%.1fM", n / 1_000_000) }
        if n >= 1_000 { return String(format: "%.0fK", n / 1_000) }
        return String(format: "%.0f", n)
    }

    private func shortDate(_ ymd: String) -> String {
        let parts = ymd.split(separator: "-")
        guard parts.count == 3 else { return ymd }
        return "\(parts[1])/\(parts[2])"
    }
}

private struct TrendChart: View {
    let bars: [TrendBar]
    let maxValue: Double
    let avgValue: Double
    let metric: (TrendBar) -> Double
    let formatValue: (Double) -> String
    let barGap: CGFloat

    @State private var hoveredBarID: TrendBar.ID?

    private var peakBarID: TrendBar.ID? {
        bars.filter { metric($0) > 0 }.max(by: { metric($0) < metric($1) })?.id
    }

    var body: some View {
        let avgFraction = maxValue > 0 ? CGFloat(min(avgValue / maxValue, 1.0)) : 0

        ZStack(alignment: .bottomLeading) {
            HStack(alignment: .bottom, spacing: barGap) {
                ForEach(bars) { bar in
                    BarColumn(
                        bar: bar,
                        value: metric(bar),
                        maxValue: maxValue,
                        isHovered: hoveredBarID == bar.id,
                        isPeak: bar.id == peakBarID
                    )
                    .onHover { hovering in
                        hoveredBarID = hovering ? bar.id : (hoveredBarID == bar.id ? nil : hoveredBarID)
                    }
                }
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .frame(height: trendChartHeight, alignment: .bottom)

            GeometryReader { geo in
                Path { p in
                    let y = geo.size.height - (geo.size.height * avgFraction)
                    p.move(to: CGPoint(x: 0, y: y))
                    p.addLine(to: CGPoint(x: geo.size.width, y: y))
                }
                .stroke(Color.secondary.opacity(0.5), style: StrokeStyle(lineWidth: 1, dash: [3, 3]))
            }
            .frame(height: trendChartHeight)
            .allowsHitTesting(false)
        }
        .frame(height: trendChartHeight)
        .overlay(alignment: .bottomLeading) {
            if let hoveredBar {
                BarTooltipCard(bar: hoveredBar, value: metric(hoveredBar), formatValue: formatValue)
                    .padding(.top, 6)
                    .offset(y: 92)
                    .transition(.opacity)
                    .allowsHitTesting(false)
                    .zIndex(10)
            }
        }
        .animation(.easeInOut(duration: 0.12), value: hoveredBarID)
    }

    private var hoveredBar: TrendBar? {
        guard let id = hoveredBarID else { return nil }
        return bars.first { $0.id == id }
    }
}

private struct BarColumn: View {
    let bar: TrendBar
    let value: Double
    let maxValue: Double
    let isHovered: Bool
    let isPeak: Bool

    var body: some View {
        let fraction = maxValue > 0 ? CGFloat(value / maxValue) : 0
        let height = max(2, trendChartHeight * fraction)

        VStack(spacing: 0) {
            Spacer(minLength: 0)
            if isPeak && value > 0 {
                RoundedRectangle(cornerRadius: 2)
                    .fill(Color.yellow.opacity(0.85))
                    .frame(maxWidth: .infinity)
                    .frame(height: max(2, trendChartHeight * 0.05))
            }
            RoundedRectangle(cornerRadius: 2)
                .fill(barColor)
                .frame(maxWidth: .infinity)
                .frame(height: height)
                .overlay(
                    RoundedRectangle(cornerRadius: 2)
                        .stroke(Theme.brandAccent.opacity(isHovered ? 0.9 : 0), lineWidth: 1)
                )
                .scaleEffect(x: isHovered ? 1.08 : 1.0, y: 1.0, anchor: .bottom)
                .animation(.easeOut(duration: 0.12), value: isHovered)
        }
        .contentShape(Rectangle())
    }

    private var barColor: Color {
        if bar.isToday { return Theme.brandAccent }
        if value <= 0 { return Color.secondary.opacity(0.15) }
        if isHovered { return Theme.brandAccent.opacity(0.85) }
        let ratio = maxValue > 0 ? value / maxValue : 0
        return Theme.brandAccent.opacity(0.42 + ratio * 0.48)
    }
}

private struct BarTooltipCard: View {
    let bar: TrendBar
    /// Value to display in the tooltip header. Matches the metric the trend chart
    /// is currently using (tokens when the .all-providers view has token data,
    /// cost when provider-filtered views force a $ fallback). Passing this in keeps
    /// the tooltip in sync with the chart instead of always reading bar.tokens,
    /// which is zero for provider-filtered days.
    let value: Double
    let formatValue: (Double) -> String
    @Environment(\.colorScheme) private var colorScheme

    private var backgroundFill: Color {
        colorScheme == .dark ? Color.white : Color.black
    }

    private var primaryText: Color {
        colorScheme == .dark ? Color.black : Color.white
    }

    private var secondaryText: Color {
        colorScheme == .dark ? Color.black.opacity(0.7) : Color.white.opacity(0.72)
    }

    private var tertiaryText: Color {
        colorScheme == .dark ? Color.black.opacity(0.5) : Color.white.opacity(0.52)
    }

    private var borderStroke: Color {
        colorScheme == .dark ? Color.black.opacity(0.12) : Color.white.opacity(0.12)
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 5) {
            HStack(alignment: .firstTextBaseline) {
                Text(prettyDate(bar.date))
                    .font(.system(size: 11, weight: .semibold))
                    .foregroundStyle(primaryText)
                Spacer()
                Text("\(formatValue(value))")
                    .font(.codeMono(size: 10.5, weight: .semibold))
                    .foregroundStyle(Theme.brandAccent)
            }

            if !bar.topModels.isEmpty {
                VStack(alignment: .leading, spacing: 3) {
                    ForEach(Array(bar.topModels.prefix(4).enumerated()), id: \.offset) { idx, m in
                        HStack(spacing: 6) {
                            RoundedRectangle(cornerRadius: 1)
                                .fill(Theme.brandAccent.opacity(0.75 - Double(idx) * 0.12))
                                .frame(width: 3, height: 12)
                            Text(m.name)
                                .font(.system(size: 10, weight: .medium))
                                .foregroundStyle(primaryText)
                                .lineLimit(1)
                            Spacer()
                            if m.cost > 0 {
                                Text(m.cost.asCompactCurrency())
                                    .font(.codeMono(size: 9.5, weight: .semibold))
                                    .foregroundStyle(secondaryText)
                            }
                            Text("\(formatTokensCompact(Double(m.totalTokens))) tok")
                                .font(.codeMono(size: 9.5, weight: .medium))
                                .foregroundStyle(tertiaryText)
                        }
                    }
                }
            }
        }
        .padding(11)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(
            RoundedRectangle(cornerRadius: 8)
                .fill(backgroundFill)
        )
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(borderStroke, lineWidth: 0.5)
        )
        .shadow(color: Color.black.opacity(0.35), radius: 10, y: 4)
    }

    private func formatTokensCompact(_ n: Double) -> String {
        if n >= 1_000_000 { return String(format: "%.1fM", n / 1_000_000) }
        if n >= 1_000 { return String(format: "%.0fK", n / 1_000) }
        return String(format: "%.0f", n)
    }
}

private func prettyDate(_ ymd: String) -> String {
    guard let date = yyyymmdd.date(from: ymd) else { return ymd }
    return prettyDayFormat.string(from: date)
}

private struct MiniStat: View {
    let label: String
    let value: String

    var body: some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.system(size: 9.5, weight: .medium))
                .foregroundStyle(.tertiary)
            Text(value)
                .font(.system(size: 11.5, weight: .semibold))
                .monospacedDigit()
                .foregroundStyle(.primary)
        }
        .padding(.horizontal, 8)
        .padding(.vertical, 5)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(
            RoundedRectangle(cornerRadius: 6)
                .fill(Color(nsColor: .separatorColor).opacity(0.35))
        )
    }
}

private struct TrendBar: Identifiable {
    var id: String { date }
    let date: String
    let cost: Double
    let inputTokens: Double
    let outputTokens: Double
    let isToday: Bool
    let topModels: [DailyModelBreakdown]

    var tokens: Double { inputTokens + outputTokens }
}

private struct TrendStats {
    let totalThisWindow: Double
    let avgPerDay: Double
    let peak: TrendBar?
    let activeDays: Int
    let deltaPercent: Double?
    let yesterdayBar: TrendBar?
}

private func buildTrendBars(from days: [DailyHistoryEntry], dayCount: Int) -> [TrendBar] {
    let calendar = gregorianCalendar
    let formatter = yyyymmdd
    let entryByDate = Dictionary(days.map { ($0.date, $0) }, uniquingKeysWith: { _, new in new })
    let today = calendar.startOfDay(for: Date())
    let todayKey = formatter.string(from: today)

    var bars: [TrendBar] = []
    for offset in (0..<dayCount).reversed() {
        guard let d = calendar.date(byAdding: .day, value: -offset, to: today) else { continue }
        let key = formatter.string(from: d)
        let entry = entryByDate[key]
        bars.append(TrendBar(
            date: key,
            cost: entry?.cost ?? 0,
            inputTokens: Double(entry?.inputTokens ?? 0),
            outputTokens: Double(entry?.outputTokens ?? 0),
            isToday: key == todayKey,
            topModels: entry?.topModels ?? []
        ))
    }
    return bars
}

private func computeTrendStats(bars: [TrendBar], allDays: [DailyHistoryEntry], dayCount: Int) -> TrendStats {
    let total = bars.reduce(0.0) { $0 + $1.cost }
    let active = bars.filter { $0.cost > 0 }.count
    let avg = bars.isEmpty ? 0 : total / Double(bars.count)
    let peak = bars.filter { $0.cost > 0 }.max(by: { $0.cost < $1.cost })

    let calendar = gregorianCalendar
    let formatter = yyyymmdd
    let today = calendar.startOfDay(for: Date())
    let priorWindowStart = calendar.date(byAdding: .day, value: -(2 * dayCount - 1), to: today)
    let thisWindowStart = calendar.date(byAdding: .day, value: -(dayCount - 1), to: today)
    var deltaPercent: Double? = nil
    if let priorStart = priorWindowStart, let thisStart = thisWindowStart {
        let priorStartStr = formatter.string(from: priorStart)
        let thisStartStr = formatter.string(from: thisStart)
        let priorTotal = allDays
            .filter { $0.date >= priorStartStr && $0.date < thisStartStr }
            .reduce(0.0) { $0 + $1.cost }
        if priorTotal > 0 {
            deltaPercent = ((total - priorTotal) / priorTotal) * 100
        }
    }

    let yesterdayDate = calendar.date(byAdding: .day, value: -1, to: today)
    let yesterdayKey = yesterdayDate.map { formatter.string(from: $0) }
    let yesterdayBar = bars.first(where: { $0.date == yesterdayKey })

    return TrendStats(
        totalThisWindow: total,
        avgPerDay: avg,
        peak: peak,
        activeDays: active,
        deltaPercent: deltaPercent,
        yesterdayBar: yesterdayBar
    )
}

// MARK: - Calendar

private struct ContributionHeatmapInsight: View {
    let days: [DailyHistoryEntry]

    private let cellSize: CGFloat = 8
    private let cellGap: CGFloat = 3
    private let weekdayLabelWidth: CGFloat = 26
    @State private var hoveredDayID: ContributionDay.ID?

    var body: some View {
        GeometryReader { geo in
            let weekCount = adaptiveWeekCount(for: geo.size.width)
            let weeks = buildContributionWeeks(from: days, weekCount: weekCount)
            let stats = computeContributionStats(weeks: weeks)
            let hoveredDay = weeks.flatMap(\.days).first { $0.id == hoveredDayID }

            VStack(alignment: .leading, spacing: 10) {
                HStack(alignment: .firstTextBaseline) {
                    VStack(alignment: .leading, spacing: 1) {
                        Text("Daily activity")
                            .font(.system(size: 10, weight: .medium))
                            .foregroundStyle(.tertiary)
                        Text(stats.total.asCurrency())
                            .font(.system(size: 18, weight: .semibold, design: .rounded))
                            .monospacedDigit()
                            .foregroundStyle(.primary)
                    }
                    Spacer()
                    Text("\(stats.activeDays) active days")
                        .font(.system(size: 10.5, weight: .medium))
                        .monospacedDigit()
                        .foregroundStyle(Theme.brandAccent)
                }

                HStack(alignment: .top, spacing: 6) {
                    VStack(alignment: .trailing, spacing: cellGap) {
                        ForEach(0..<7, id: \.self) { idx in
                            Text(weekdayLabel(for: idx))
                                .font(.system(size: 8.5, weight: .medium))
                                .foregroundStyle(.tertiary)
                                .frame(width: weekdayLabelWidth, height: cellSize, alignment: .trailing)
                        }
                    }

                    HStack(alignment: .top, spacing: cellGap) {
                        ForEach(weeks) { week in
                            VStack(spacing: cellGap) {
                                ForEach(week.days) { day in
                                    ContributionCell(
                                        day: day,
                                        size: cellSize,
                                        isHovered: hoveredDayID == day.id
                                    )
                                    .onHover { hovering in
                                        hoveredDayID = hovering ? day.id : (hoveredDayID == day.id ? nil : hoveredDayID)
                                    }
                                }
                            }
                        }
                    }
                    .frame(maxWidth: .infinity, alignment: .trailing)
                }

                ContributionDayDetail(day: hoveredDay, fallbackStats: stats)
                    .animation(.easeInOut(duration: 0.12), value: hoveredDayID)

                HStack(spacing: 14) {
                    MiniStat(label: "Peak day", value: stats.peakLabel)
                    MiniStat(label: "Avg active", value: stats.avgActive.asCompactCurrency())
                    MiniStat(label: "Streak", value: "\(stats.currentStreak)d")
                }
            }
        }
        .frame(height: 216)
    }

    private func adaptiveWeekCount(for width: CGFloat) -> Int {
        let available = max(0, width - weekdayLabelWidth - 10)
        let raw = Int(floor((available + cellGap) / (cellSize + cellGap)))
        return min(max(raw, 1), 52)
    }

    private func weekdayLabel(for index: Int) -> String {
        switch index {
        case 0: return "Mon"
        case 2: return "Wed"
        case 4: return "Fri"
        case 6: return "Sun"
        default: return ""
        }
    }
}

private struct ContributionCell: View {
    let day: ContributionDay
    let size: CGFloat
    let isHovered: Bool

    var body: some View {
        RoundedRectangle(cornerRadius: 2)
            .fill(fillColor)
            .frame(width: size, height: size)
            .overlay(
                RoundedRectangle(cornerRadius: 2)
                    .stroke(strokeColor, lineWidth: isHovered || day.isToday ? 1 : 0)
            )
            .scaleEffect(isHovered ? 1.35 : 1.0)
            .animation(.easeOut(duration: 0.10), value: isHovered)
            .help(day.helpText)
            .accessibilityLabel(day.helpText)
    }

    private var strokeColor: Color {
        if isHovered { return Theme.brandAccent.opacity(0.95) }
        if day.isToday { return Theme.brandAccent.opacity(0.95) }
        return Color.clear
    }

    private var fillColor: Color {
        if day.isFuture { return Color.secondary.opacity(0.06) }
        if isHovered { return Theme.brandAccent.opacity(0.95) }
        switch day.level {
        case 0: return Color.secondary.opacity(0.14)
        case 1: return Theme.brandAccent.opacity(0.30)
        case 2: return Theme.brandAccent.opacity(0.48)
        case 3: return Theme.brandAccent.opacity(0.66)
        default: return Theme.brandAccent.opacity(0.88)
        }
    }
}

private struct ContributionDayDetail: View {
    let day: ContributionDay?
    let fallbackStats: ContributionStats

    var body: some View {
        HStack(spacing: 12) {
            VStack(alignment: .leading, spacing: 2) {
                Text(title)
                    .font(.system(size: 10, weight: .medium))
                    .foregroundStyle(.tertiary)
                Text(value)
                    .font(.system(size: 13, weight: .semibold))
                    .monospacedDigit()
                    .foregroundStyle(.primary)
                    .lineLimit(1)
            }

            Spacer(minLength: 8)

            DetailMetric(label: "Calls", value: calls)
            DetailMetric(label: "Tokens", value: tokens)
        }
        .padding(.horizontal, 9)
        .padding(.vertical, 7)
        .frame(maxWidth: .infinity, minHeight: 42, alignment: .leading)
        .background(
            RoundedRectangle(cornerRadius: 6)
                .fill(Color(nsColor: .separatorColor).opacity(0.25))
        )
    }

    private var title: String {
        // The header already shows the period total and active-day count, so
        // the resting state is a short hover hint — not a duplicate of those
        // (and not the full sentence that previously overflowed and truncated).
        guard let day else { return "Daily detail" }
        return prettyDate(day.date)
    }

    private var value: String {
        guard let day else { return "Hover a day" }
        if day.isFuture { return "Future day" }
        if day.cost <= 0 && day.calls == 0 { return "No tracked usage" }
        return day.cost.asCompactCurrency()
    }

    private var calls: String {
        guard let day, !day.isFuture else { return "—" }
        return "\(day.calls)"
    }

    private var tokens: String {
        guard let day, !day.isFuture else { return "—" }
        return formatTokensForContribution(day.totalTokens)
    }
}

private struct DetailMetric: View {
    let label: String
    let value: String

    var body: some View {
        VStack(alignment: .trailing, spacing: 2) {
            Text(label)
                .font(.system(size: 9, weight: .medium))
                .foregroundStyle(.tertiary)
            Text(value)
                .font(.codeMono(size: 11, weight: .semibold))
                .foregroundStyle(.primary)
                .lineLimit(1)
        }
        .frame(minWidth: 42, alignment: .trailing)
    }
}

struct ContributionWeek: Identifiable, Equatable {
    let startDate: String
    let days: [ContributionDay]

    var id: String { startDate }
}

struct ContributionDay: Identifiable, Equatable {
    let date: String
    let cost: Double
    let calls: Int
    let inputTokens: Int
    let outputTokens: Int
    let level: Int
    let isToday: Bool
    let isFuture: Bool

    var id: String { date }
    var totalTokens: Int { inputTokens + outputTokens }

    @MainActor var helpText: String {
        if isFuture { return "\(prettyDate(date)): future day" }
        if cost <= 0 && calls == 0 { return "\(prettyDate(date)): no tracked usage" }
        return "\(prettyDate(date)): \(cost.asCompactCurrency()), \(calls) calls, \(formatTokensForContribution(totalTokens)) tokens"
    }
}

struct ContributionStats: Equatable {
    let total: Double
    let activeDays: Int
    let avgActive: Double
    let peakLabel: String
    let currentStreak: Int
}

func contributionLevel(value: Double, maxValue: Double) -> Int {
    guard value > 0, maxValue > 0 else { return 0 }
    let ratio = min(max(value / maxValue, 0), 1)
    if ratio < 0.25 { return 1 }
    if ratio < 0.50 { return 2 }
    if ratio < 0.75 { return 3 }
    return 4
}

func buildContributionWeeks(
    from days: [DailyHistoryEntry],
    weekCount: Int,
    now: Date = Date(),
    calendar: Calendar = gregorianCalendar,
    formatter: DateFormatter = yyyymmdd
) -> [ContributionWeek] {
    let today = calendar.startOfDay(for: now)
    let todayKey = formatter.string(from: today)
    let visibleWeekCount = min(max(weekCount, 1), 52)
    let entryByDate = Dictionary(days.map { ($0.date, $0) }, uniquingKeysWith: { _, new in new })
    guard
        let thisWeekStart = startOfContributionWeek(containing: today, calendar: calendar),
        let firstWeekStart = calendar.date(byAdding: .weekOfYear, value: -(visibleWeekCount - 1), to: thisWeekStart)
    else {
        return []
    }

    var visibleKeys: [String] = []
    for offset in 0..<(visibleWeekCount * 7) {
        guard let date = calendar.date(byAdding: .day, value: offset, to: firstWeekStart) else { continue }
        if date <= today { visibleKeys.append(formatter.string(from: date)) }
    }
    let maxCost = visibleKeys.compactMap { entryByDate[$0]?.cost }.max() ?? 0

    var weeks: [ContributionWeek] = []
    for weekOffset in 0..<visibleWeekCount {
        guard let weekStart = calendar.date(byAdding: .weekOfYear, value: weekOffset, to: firstWeekStart) else { continue }
        let weekStartKey = formatter.string(from: weekStart)
        var contributionDays: [ContributionDay] = []

        for dayOffset in 0..<7 {
            guard let date = calendar.date(byAdding: .day, value: dayOffset, to: weekStart) else { continue }
            let key = formatter.string(from: date)
            let entry = entryByDate[key]
            let isFuture = date > today
            let cost = isFuture ? 0 : (entry?.cost ?? 0)
            contributionDays.append(ContributionDay(
                date: key,
                cost: cost,
                calls: isFuture ? 0 : (entry?.calls ?? 0),
                inputTokens: isFuture ? 0 : (entry?.inputTokens ?? 0),
                outputTokens: isFuture ? 0 : (entry?.outputTokens ?? 0),
                level: isFuture ? 0 : contributionLevel(value: cost, maxValue: maxCost),
                isToday: key == todayKey,
                isFuture: isFuture
            ))
        }

        weeks.append(ContributionWeek(startDate: weekStartKey, days: contributionDays))
    }

    return weeks
}

@MainActor func computeContributionStats(weeks: [ContributionWeek]) -> ContributionStats {
    let days = weeks.flatMap(\.days).filter { !$0.isFuture }
    let active = days.filter { $0.cost > 0 }
    let total = active.reduce(0.0) { $0 + $1.cost }
    let avg = active.isEmpty ? 0 : total / Double(active.count)
    let peak = active.max(by: { $0.cost < $1.cost })
    let peakLabel = peak.map { "\($0.cost.asCompactCurrency()) on \(shortContributionDate($0.date))" } ?? "—"

    var streak = 0
    for day in days.reversed() {
        if day.cost > 0 {
            streak += 1
        } else {
            break
        }
    }

    return ContributionStats(
        total: total,
        activeDays: active.count,
        avgActive: avg,
        peakLabel: peakLabel,
        currentStreak: streak
    )
}

private func startOfContributionWeek(containing date: Date, calendar: Calendar) -> Date? {
    let start = calendar.startOfDay(for: date)
    let weekday = calendar.component(.weekday, from: start)
    let daysFromMonday = (weekday + 5) % 7
    return calendar.date(byAdding: .day, value: -daysFromMonday, to: start)
}

private func shortContributionDate(_ ymd: String) -> String {
    guard let date = yyyymmdd.date(from: ymd) else { return ymd }
    return mmmDayFormat.string(from: date)
}

private func formatTokensForContribution(_ n: Int) -> String {
    if n >= 1_000_000 { return String(format: "%.1fM", Double(n) / 1_000_000) }
    if n >= 1_000 { return String(format: "%.0fK", Double(n) / 1_000) }
    return "\(n)"
}

// MARK: - Forecast

private struct ForecastInsight: View {
    let days: [DailyHistoryEntry]

    var body: some View {
        let stats = computeForecast(days: days)
        VStack(alignment: .leading, spacing: 10) {
            HStack(alignment: .firstTextBaseline) {
                VStack(alignment: .leading, spacing: 2) {
                    Text("Month-to-date")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Text(stats.mtd.asCurrency())
                        .font(.system(size: 22, weight: .semibold, design: .rounded))
                        .monospacedDigit()
                        .foregroundStyle(Theme.brandAccent)
                }
                Spacer()
                VStack(alignment: .trailing, spacing: 2) {
                    Text("On pace for")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Text(stats.projection.asCurrency())
                        .font(.system(size: 16, weight: .semibold))
                        .monospacedDigit()
                }
            }

            HStack(spacing: 14) {
                ForecastStat(label: "Avg/day (this wk)", value: stats.weekAvg.asCompactCurrency())
                ForecastStat(label: "Yesterday", value: stats.yesterday.asCompactCurrency())
                ForecastStat(label: "Last 7d", value: stats.weekTotal.asCompactCurrency())
            }

            if let prevTotal = stats.previousMonthTotal {
                HStack(spacing: 4) {
                    Image(systemName: stats.projection > prevTotal ? "arrow.up.right" : "arrow.down.right")
                        .font(.system(size: 9, weight: .bold))
                    Text(comparisonText(projection: stats.projection, previous: prevTotal))
                        .font(.system(size: 10.5))
                        .monospacedDigit()
                }
                .foregroundStyle(Theme.brandAccent)
            }
        }
    }

    private func comparisonText(projection: Double, previous: Double) -> String {
        guard previous > 0 else { return "no prior month" }
        let diff = ((projection - previous) / previous) * 100
        let sign = diff >= 0 ? "+" : ""
        return "\(sign)\(String(format: "%.0f", diff))% vs last month (\(previous.asCompactCurrency()))"
    }
}

private struct ForecastStat: View {
    let label: String
    let value: String
    var body: some View {
        VStack(alignment: .leading, spacing: 1) {
            Text(label)
                .font(.system(size: 9.5, weight: .medium))
                .foregroundStyle(.tertiary)
            Text(value)
                .font(.system(size: 12, weight: .semibold))
                .monospacedDigit()
                .foregroundStyle(.primary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }
}

private struct ForecastStats {
    let mtd: Double
    let projection: Double
    let weekAvg: Double
    let weekTotal: Double
    let yesterday: Double
    let previousMonthTotal: Double?
}

private func computeForecast(days: [DailyHistoryEntry]) -> ForecastStats {
    let calendar = gregorianCalendar
    let formatter = yyyymmdd
    let now = Date()
    let comps = calendar.dateComponents([.year, .month, .day], from: now)
    guard
        let firstOfMonth = calendar.date(from: DateComponents(year: comps.year, month: comps.month, day: 1)),
        let rangeOfMonth = calendar.range(of: .day, in: .month, for: firstOfMonth)
    else {
        return ForecastStats(mtd: 0, projection: 0, weekAvg: 0, weekTotal: 0, yesterday: 0, previousMonthTotal: nil)
    }

    let firstStr = formatter.string(from: firstOfMonth)
    let totalDays = rangeOfMonth.count
    let dayOfMonth = comps.day ?? 1

    let mtdEntries = days.filter { $0.date >= firstStr }
    let mtd = mtdEntries.reduce(0.0) { $0 + $1.cost }
    let avgPerElapsedDay = dayOfMonth > 0 ? mtd / Double(dayOfMonth) : 0
    let projection = avgPerElapsedDay * Double(totalDays)

    let weekStart = calendar.date(byAdding: .day, value: -6, to: calendar.startOfDay(for: now))
    let weekStartStr = weekStart.map { formatter.string(from: $0) } ?? ""
    let weekEntries = days.filter { $0.date >= weekStartStr }
    let weekTotal = weekEntries.reduce(0.0) { $0 + $1.cost }
    let weekAvg = weekTotal / 7.0

    let yesterdayDate = calendar.date(byAdding: .day, value: -1, to: calendar.startOfDay(for: now))
    let yesterdayStr = yesterdayDate.map { formatter.string(from: $0) } ?? ""
    let yesterday = days.first(where: { $0.date == yesterdayStr })?.cost ?? 0

    var previousMonthTotal: Double? = nil
    if
        let prevMonthDate = calendar.date(byAdding: .month, value: -1, to: firstOfMonth),
        let prevRange = calendar.range(of: .day, in: .month, for: prevMonthDate),
        let prevFirst = calendar.date(from: DateComponents(year: calendar.component(.year, from: prevMonthDate), month: calendar.component(.month, from: prevMonthDate), day: 1)),
        let prevLast = calendar.date(byAdding: .day, value: prevRange.count - 1, to: prevFirst)
    {
        let prevFirstStr = formatter.string(from: prevFirst)
        let prevLastStr = formatter.string(from: prevLast)
        let prevEntries = days.filter { $0.date >= prevFirstStr && $0.date <= prevLastStr }
        if !prevEntries.isEmpty {
            previousMonthTotal = prevEntries.reduce(0.0) { $0 + $1.cost }
        }
    }

    return ForecastStats(
        mtd: mtd,
        projection: projection,
        weekAvg: weekAvg,
        weekTotal: weekTotal,
        yesterday: yesterday,
        previousMonthTotal: previousMonthTotal
    )
}

// MARK: - Pulse

private struct PulseInsight: View {
    let payload: MenubarPayload

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack(spacing: 10) {
                PulseTile(label: "Cache hit", value: cacheHitText, color: Theme.brandAccent)
                PulseTile(label: "1-shot", value: oneShotText, color: oneShotColor)
                PulseTile(
                    label: "Cost / session",
                    value: payload.current.sessions > 0
                        ? (payload.current.cost / Double(payload.current.sessions)).asCompactCurrency()
                        : "—",
                    color: .secondary
                )
            }
            CostPerEditCaption(models: payload.current.modelEfficiency)
        }
    }

    private var cacheHitText: String {
        let v = payload.current.cacheHitPercent
        return v <= 0 ? "—" : String(format: "%.0f%%", v)
    }

    private var oneShotText: String {
        guard let r = payload.current.oneShotRate else { return "—" }
        return String(format: "%.0f%%", r * 100)
    }

    private var oneShotColor: Color {
        payload.current.oneShotRate == nil ? .secondary : Theme.brandAccent
    }
}

private struct PulseTile: View {
    let label: String
    let value: String
    let color: Color

    var body: some View {
        VStack(alignment: .leading, spacing: 3) {
            Text(label)
                .font(.system(size: 10, weight: .medium))
                .foregroundStyle(.tertiary)
            Text(value)
                .font(.system(size: 18, weight: .semibold, design: .rounded))
                .monospacedDigit()
                .foregroundStyle(color)
        }
        .padding(.horizontal, 10)
        .padding(.vertical, 8)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(
            RoundedRectangle(cornerRadius: 6)
                .fill(Color.secondary.opacity(0.06))
        )
    }
}

private struct CostPerEditCaption: View {
    let models: [ModelEfficiencyEntry]

    var body: some View {
        let valid = models.compactMap { m -> (String, Double)? in
            guard let cpe = m.costPerEdit, cpe > 0 else { return nil }
            return (m.name, cpe)
        }.sorted(by: { $0.1 < $1.1 })

        if let best = valid.first {
            HStack(spacing: 4) {
                Image(systemName: "pencil.line")
                    .font(.system(size: 9, weight: .medium))
                    .foregroundStyle(.tertiary)
                Text("Cost/edit")
                    .font(.system(size: 10, weight: .medium))
                    .foregroundStyle(.tertiary)
                Text(formatCPE(best.1))
                    .font(.codeMono(size: 10.5, weight: .semibold))
                    .foregroundStyle(Theme.brandAccent)
                Text(best.0)
                    .font(.system(size: 10))
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
                if valid.count > 1, let worst = valid.last, worst.0 != best.0 {
                    Text("—")
                        .font(.system(size: 9))
                        .foregroundStyle(.quaternary)
                    Text(formatCPE(worst.1))
                        .font(.codeMono(size: 10.5, weight: .semibold))
                        .foregroundStyle(.primary)
                    Text(worst.0)
                        .font(.system(size: 10))
                        .foregroundStyle(.secondary)
                        .lineLimit(1)
                }
                Spacer()
            }
        }
    }

    private func formatCPE(_ v: Double) -> String {
        if v < 0.01 { return String(format: "$%.3f", v) }
        return String(format: "$%.2f", v)
    }
}

/// Connects optimize findings directly to plan utilization: "address N findings to recover X
/// tokens" framed as the same currency the rest of the Plan view uses (effective tokens).
/// Scoped to whatever period the user selected (today / 7d / 30d / month / all).
private struct OptimizeSavingsBadge: View {
    let payload: MenubarPayload

    var body: some View {
        let findingCount = payload.optimize.findingCount
        let savingsUSD = payload.optimize.savingsUSD
        if findingCount == 0 || savingsUSD <= 0 {
            EmptyView()
        } else {
            Button { openOptimize() } label: {
                HStack(spacing: 6) {
                    Image(systemName: "lightbulb.fill")
                        .font(.system(size: 10, weight: .semibold))
                        .foregroundStyle(Theme.brandAccent)
                    Text(captionText(findingCount: findingCount, savingsUSD: savingsUSD))
                        .font(.system(size: 11, weight: .medium))
                        .foregroundStyle(.primary)
                    Spacer()
                    Image(systemName: "chevron.right")
                        .font(.system(size: 8, weight: .semibold))
                        .foregroundStyle(.tertiary)
                }
                .padding(.horizontal, 10)
                .padding(.vertical, 7)
                .background(
                    RoundedRectangle(cornerRadius: 6)
                        .fill(Theme.brandAccent.opacity(0.10))
                )
            }
            .buttonStyle(.plain)
            .padding(.top, 2)
        }
    }

    private func captionText(findingCount: Int, savingsUSD: Double) -> String {
        let tokens = savingsUSD / 9.0 * 1_000_000  // ~$9/M effective tokens (Sonnet-weighted approx)
        let tokensLabel = formatTokens(tokens)
        let plural = findingCount == 1 ? "finding" : "findings"
        return "Save ~\(savingsUSD.asCompactCurrency()) / ~\(tokensLabel) tokens · \(findingCount) \(plural)"
    }

    private func openOptimize() {
        TerminalLauncher.open(subcommand: ["optimize"])
    }

    private func formatTokens(_ n: Double) -> String {
        if n >= 1_000_000 { return String(format: "%.1fM", n / 1_000_000) }
        if n >= 1_000 { return String(format: "%.0fK", n / 1_000) }
        return String(format: "%.0f", n)
    }
}

// MARK: - Stats

private struct StatsInsight: View {
    let payload: MenubarPayload

    var body: some View {
        let stats = computeAllStats(payload: payload)

        VStack(alignment: .leading, spacing: 10) {
            HStack(alignment: .top, spacing: 14) {
                VStack(alignment: .leading, spacing: 8) {
                    StatRow(label: "Favorite model", value: stats.favoriteModel)
                    StatRow(label: "Active days (month)", value: stats.activeDaysFraction)
                    StatRow(label: "Most active day", value: stats.mostActiveDay)
                    StatRow(label: "Peak day spend", value: stats.peakDaySpend)
                }
                .frame(maxWidth: .infinity, alignment: .leading)

                VStack(alignment: .leading, spacing: 8) {
                    StatRow(label: "Sessions today", value: "\(payload.current.sessions)")
                    StatRow(label: "Calls today", value: payload.current.calls.asThousandsSeparated())
                    StatRow(label: "Current streak", value: stats.currentStreak)
                    StatRow(label: "Longest streak", value: stats.longestStreak)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
            }

            if let lifetime = stats.lifetimeTotal {
                Divider().opacity(0.5)
                HStack {
                    Text("Tracked spend (last \(stats.historyDayCount) days)")
                        .font(.system(size: 10.5, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Spacer()
                    Text(lifetime.asCurrency())
                        .font(.system(size: 13, weight: .semibold, design: .rounded))
                        .monospacedDigit()
                        .foregroundStyle(Theme.brandAccent)
                }
            }

            if !payload.current.topProjects.isEmpty {
                Divider().opacity(0.5)
                TopProjectsList(projects: payload.current.topProjects)
            }

            if let top = payload.current.topSessions.first, top.cost > 0 {
                HStack(spacing: 4) {
                    Image(systemName: "flame")
                        .font(.system(size: 9, weight: .medium))
                        .foregroundStyle(Theme.brandAccent)
                    Text("Costliest session")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Spacer()
                    Text(top.cost.asCompactCurrency())
                        .font(.codeMono(size: 10.5, weight: .semibold))
                        .foregroundStyle(.secondary)
                        .monospacedDigit()
                    Text("· \(projectDisplayName(top.project))")
                        .font(.system(size: 10))
                        .foregroundStyle(.tertiary)
                        .lineLimit(1)
                }
            }

        }
    }
}

private struct RetryTaxSection: View {
    let retryTax: RetryTax
    let totalCost: Double
    @State private var expanded = false

    var body: some View {
        if retryTax.totalUSD > 0 {
            Divider().opacity(0.5)
            VStack(alignment: .leading, spacing: 4) {
                HStack(spacing: 4) {
                    Image(systemName: "arrow.2.squarepath")
                        .font(.system(size: 9, weight: .medium))
                        .foregroundStyle(.orange)
                    Text("Retry tax")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Spacer()
                    Text(retryTax.totalUSD.asCompactCurrency())
                        .font(.codeMono(size: 11, weight: .bold))
                        .foregroundStyle(.orange)
                        .monospacedDigit()
                    if totalCost > 0 {
                        Text("(\(Int((retryTax.totalUSD / totalCost * 100).rounded()))%)")
                            .font(.system(size: 9.5))
                            .foregroundStyle(.tertiary)
                    }
                    Image(systemName: "chevron.right")
                        .font(.system(size: 7, weight: .bold))
                        .foregroundStyle(.quaternary)
                        .rotationEffect(.degrees(expanded ? 90 : 0))
                }
                .contentShape(Rectangle())
                .onTapGesture {
                    withAnimation(.spring(response: 0.3, dampingFraction: 0.85)) {
                        expanded.toggle()
                    }
                }

                Text("\(retryTax.retries) retries across \(retryTax.editTurns) edits")
                    .font(.system(size: 9.5))
                    .foregroundStyle(.quaternary)

                if expanded {
                    VStack(alignment: .leading, spacing: 3) {
                        ForEach(Array(retryTax.byModel.enumerated()), id: \.offset) { idx, model in
                            HStack(spacing: 0) {
                                Text(model.name)
                                    .font(.system(size: 9.5, weight: .medium))
                                    .foregroundStyle(.secondary)
                                Spacer()
                                if let rpe = model.retriesPerEdit {
                                    Text(String(format: "%.1f ret/edit", rpe))
                                        .font(.system(size: 9))
                                        .foregroundStyle(.quaternary)
                                        .padding(.trailing, 8)
                                }
                                Text(model.taxUSD.asCompactCurrency())
                                    .font(.codeMono(size: 10, weight: .semibold))
                                    .foregroundStyle(.orange.opacity(0.85))
                                    .monospacedDigit()
                            }
                            .padding(.vertical, 2)
                            .padding(.horizontal, 6)
                            .background(RoundedRectangle(cornerRadius: 4).fill(.orange.opacity(0.05)))
                            .transition(
                                .asymmetric(
                                    insertion: .opacity.combined(with: .scale(scale: 0.95, anchor: .top))
                                        .animation(.spring(response: 0.3, dampingFraction: 0.8).delay(Double(idx) * 0.03)),
                                    removal: .opacity.animation(.easeOut(duration: 0.12))
                                )
                            )
                        }
                    }
                    .padding(.top, 2)
                }
            }
        }
    }
}

private struct StatRow: View {
    let label: String
    let value: String

    var body: some View {
        VStack(alignment: .leading, spacing: 1) {
            Text(label)
                .font(.system(size: 9.5, weight: .medium))
                .foregroundStyle(.tertiary)
            Text(value)
                .font(.system(size: 12, weight: .semibold))
                .monospacedDigit()
                .foregroundStyle(.primary)
        }
    }
}

private func projectDisplayName(_ path: String) -> String {
    path.split(separator: "/").last.map(String.init) ?? path
}

private struct TopProjectsList: View {
    let projects: [ProjectEntry]
    @State private var expanded: String?

    var body: some View {
        let top = Array(projects.prefix(3))
        let maxCost = top.first?.cost ?? 1

        VStack(alignment: .leading, spacing: 5) {
            ForEach(Array(top.enumerated()), id: \.offset) { idx, project in
                let expandKey = "\(idx):\(project.name)"
                let isOpen = expanded == expandKey
                VStack(alignment: .leading, spacing: 0) {
                    HStack(spacing: 6) {
                        Image(systemName: "chevron.right")
                            .font(.system(size: 7, weight: .bold))
                            .foregroundStyle(.quaternary)
                            .rotationEffect(.degrees(isOpen ? 90 : 0))
                        Text(projectDisplayName(project.name))
                            .font(.system(size: 10.5, weight: .medium))
                            .foregroundStyle(.primary)
                            .lineLimit(1)
                        Spacer()
                        Text("\(project.sessions) sess")
                            .font(.system(size: 9.5))
                            .foregroundStyle(.quaternary)
                        Text(project.cost.asCompactCurrency())
                            .font(.codeMono(size: 10.5, weight: .semibold))
                            .foregroundStyle(.secondary)
                            .monospacedDigit()
                        RoundedRectangle(cornerRadius: 2)
                            .fill(Theme.brandAccent.opacity(0.5))
                            .frame(
                                width: max(2, 40 * CGFloat(project.cost / max(maxCost, 0.01))),
                                height: 6
                            )
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        withAnimation(.spring(response: 0.3, dampingFraction: 0.85)) {
                            expanded = isOpen ? nil : expandKey
                        }
                    }

                    if isOpen, !project.sessionDetails.isEmpty {
                        SessionDetailsList(sessions: project.sessionDetails)
                            .padding(.top, 6)
                            .padding(.leading, 14)
                    }
                }
            }
        }
    }
}

private struct SessionDetailsList: View {
    let sessions: [SessionDetailEntry]

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            ForEach(Array(sessions.prefix(5).enumerated()), id: \.offset) { idx, sess in
                VStack(alignment: .leading, spacing: 3) {
                    HStack(spacing: 0) {
                        Text(sess.cost.asCompactCurrency())
                            .font(.codeMono(size: 10, weight: .semibold))
                            .foregroundStyle(.primary)
                            .monospacedDigit()
                            .frame(width: 52, alignment: .trailing)
                        Text("  \(sess.calls) calls")
                            .font(.system(size: 9))
                            .foregroundStyle(.quaternary)
                        Spacer()
                        HStack(spacing: 3) {
                            Image(systemName: "arrow.down")
                                .font(.system(size: 7, weight: .semibold))
                            Text(compactTokens(sess.inputTokens))
                        }
                        .font(.system(size: 9))
                        .foregroundStyle(.tertiary)
                        HStack(spacing: 3) {
                            Image(systemName: "arrow.up")
                                .font(.system(size: 7, weight: .semibold))
                            Text(compactTokens(sess.outputTokens))
                        }
                        .font(.system(size: 9))
                        .foregroundStyle(.tertiary)
                        .padding(.leading, 4)
                    }
                    HStack(spacing: 4) {
                        ForEach(Array(sess.models.prefix(3).enumerated()), id: \.offset) { _, model in
                            Text(model.name)
                                .font(.system(size: 8.5, weight: .medium))
                                .foregroundStyle(.secondary)
                                .padding(.horizontal, 5)
                                .padding(.vertical, 1.5)
                                .background(Theme.brandAccent.opacity(0.1))
                                .clipShape(Capsule())
                        }
                    }
                    .padding(.leading, 52)
                }
                .padding(.vertical, 3)
                .padding(.horizontal, 6)
                .background(
                    RoundedRectangle(cornerRadius: 5)
                        .fill(.primary.opacity(0.03))
                )
                .transition(
                    .asymmetric(
                        insertion: .opacity.combined(with: .scale(scale: 0.95, anchor: .top))
                            .animation(.spring(response: 0.3, dampingFraction: 0.8).delay(Double(idx) * 0.03)),
                        removal: .opacity.animation(.easeOut(duration: 0.15))
                    )
                )
            }
        }
    }

    private func compactTokens(_ n: Int) -> String {
        let d = Double(n)
        if d >= 1_000_000 { return String(format: "%.1fM", d / 1_000_000) }
        if d >= 1_000 { return String(format: "%.0fK", d / 1_000) }
        return "\(n)"
    }
}

// MARK: - Optimize

private struct OptimizeInsight: View {
    let payload: MenubarPayload

    var body: some View {
        let totalWaste = payload.current.retryTax.totalUSD + payload.current.routingWaste.totalSavingsUSD
        let cost = payload.current.cost

        VStack(alignment: .leading, spacing: 12) {
            if totalWaste > 0, cost > 0 {
                HStack(alignment: .firstTextBaseline) {
                    VStack(alignment: .leading, spacing: 2) {
                        Text("Potential savings")
                            .font(.system(size: 10, weight: .medium))
                            .foregroundStyle(.tertiary)
                        Text(totalWaste.asCompactCurrency())
                            .font(.system(size: 24, weight: .bold, design: .rounded))
                            .monospacedDigit()
                            .foregroundStyle(.orange)
                    }
                    Spacer()
                    VStack(alignment: .trailing, spacing: 2) {
                        Text("\(Int((totalWaste / cost * 100).rounded()))% of spend")
                            .font(.system(size: 11, weight: .semibold))
                            .foregroundStyle(.orange.opacity(0.8))
                        Text("could be optimized")
                            .font(.system(size: 9.5))
                            .foregroundStyle(.quaternary)
                    }
                }
                .padding(.bottom, 2)
            }

            RetryTaxSection(retryTax: payload.current.retryTax, totalCost: cost)

            RoutingWasteSection(routingWaste: payload.current.routingWaste, totalCost: cost)
        }
    }
}

private struct RoutingWasteSection: View {
    let routingWaste: RoutingWaste
    let totalCost: Double
    @State private var expanded = false

    var body: some View {
        if routingWaste.totalSavingsUSD > 0 {
            Divider().opacity(0.5)
            VStack(alignment: .leading, spacing: 4) {
                HStack(spacing: 4) {
                    Image(systemName: "arrow.triangle.swap")
                        .font(.system(size: 9, weight: .medium))
                        .foregroundStyle(.purple)
                    Text("Routing waste")
                        .font(.system(size: 10, weight: .medium))
                        .foregroundStyle(.tertiary)
                    Spacer()
                    Text(routingWaste.totalSavingsUSD.asCompactCurrency())
                        .font(.codeMono(size: 11, weight: .bold))
                        .foregroundStyle(.purple)
                        .monospacedDigit()
                    if totalCost > 0 {
                        Text("(\(Int((routingWaste.totalSavingsUSD / totalCost * 100).rounded()))%)")
                            .font(.system(size: 9.5))
                            .foregroundStyle(.tertiary)
                    }
                    Image(systemName: "chevron.right")
                        .font(.system(size: 7, weight: .bold))
                        .foregroundStyle(.quaternary)
                        .rotationEffect(.degrees(expanded ? 90 : 0))
                }
                .contentShape(Rectangle())
                .onTapGesture {
                    withAnimation(.spring(response: 0.3, dampingFraction: 0.85)) {
                        expanded.toggle()
                    }
                }

                if !routingWaste.baselineModel.isEmpty {
                    Text("vs \(routingWaste.baselineModel) @ \(routingWaste.baselineCostPerEdit.asCompactCurrency())/edit")
                        .font(.system(size: 9.5))
                        .foregroundStyle(.quaternary)
                }

                if expanded {
                    VStack(alignment: .leading, spacing: 3) {
                        ForEach(Array(routingWaste.byModel.enumerated()), id: \.offset) { idx, model in
                            HStack(spacing: 0) {
                                Text(model.name)
                                    .font(.system(size: 9.5, weight: .medium))
                                    .foregroundStyle(.secondary)
                                Spacer()
                                Text(String(format: "$%.2f/edit", model.costPerEdit))
                                    .font(.system(size: 9))
                                    .foregroundStyle(.quaternary)
                                    .padding(.trailing, 8)
                                Text(model.savingsUSD.asCompactCurrency())
                                    .font(.codeMono(size: 10, weight: .semibold))
                                    .foregroundStyle(.purple.opacity(0.85))
                                    .monospacedDigit()
                            }
                            .padding(.vertical, 2)
                            .padding(.horizontal, 6)
                            .background(RoundedRectangle(cornerRadius: 4).fill(.purple.opacity(0.05)))
                            .transition(
                                .asymmetric(
                                    insertion: .opacity.combined(with: .scale(scale: 0.95, anchor: .top))
                                        .animation(.spring(response: 0.3, dampingFraction: 0.8).delay(Double(idx) * 0.03)),
                                    removal: .opacity.animation(.easeOut(duration: 0.12))
                                )
                            )
                        }
                    }
                    .padding(.top, 2)
                }
            }
        }
    }
}

private struct AllStats {
    let favoriteModel: String
    let activeDaysFraction: String
    let mostActiveDay: String
    let peakDaySpend: String
    let currentStreak: String
    let longestStreak: String
    let lifetimeTotal: Double?
    let historyDayCount: Int
}

@MainActor private func computeAllStats(payload: MenubarPayload) -> AllStats {
    let history = payload.history.daily
    let favoriteModel = payload.current.topModels.first?.name ?? "—"

    let calendar = gregorianCalendar
    let formatter = yyyymmdd
    let displayFormatter = mmmDayFormat

    let now = Date()
    let today = calendar.startOfDay(for: now)
    let comps = calendar.dateComponents([.year, .month, .day], from: now)

    var activeDaysFraction = "—"
    if
        let firstOfMonth = calendar.date(from: DateComponents(year: comps.year, month: comps.month, day: 1)),
        let rangeOfMonth = calendar.range(of: .day, in: .month, for: firstOfMonth)
    {
        let firstStr = formatter.string(from: firstOfMonth)
        let mtdActive = history.filter { $0.date >= firstStr && $0.cost > 0 }.count
        activeDaysFraction = "\(mtdActive)/\(rangeOfMonth.count)"
    }

    let peak = history.max(by: { $0.cost < $1.cost })
    let mostActiveDay: String
    let peakDaySpend: String
    if let peak, peak.cost > 0, let date = formatter.date(from: peak.date) {
        mostActiveDay = displayFormatter.string(from: date)
        peakDaySpend = peak.cost.asCompactCurrency()
    } else {
        mostActiveDay = "—"
        peakDaySpend = "—"
    }

    let costByDate = Dictionary(history.map { ($0.date, $0.cost) }, uniquingKeysWith: +)

    var currentStreak = 0
    for offset in 0..<400 {
        guard let d = calendar.date(byAdding: .day, value: -offset, to: today) else { break }
        let key = formatter.string(from: d)
        if (costByDate[key] ?? 0) > 0 { currentStreak += 1 } else { break }
    }

    var longestStreak = 0
    var running = 0
    if let firstDate = history.map(\.date).min(),
       let lastDate = history.map(\.date).max(),
       let start = formatter.date(from: firstDate),
       let end = formatter.date(from: lastDate) {
        var cursor = start
        while cursor <= end {
            let key = formatter.string(from: cursor)
            if (costByDate[key] ?? 0) > 0 {
                running += 1
                longestStreak = max(longestStreak, running)
            } else {
                running = 0
            }
            guard let next = calendar.date(byAdding: .day, value: 1, to: cursor) else { break }
            cursor = next
        }
    }

    let lifetimeTotal: Double? = history.isEmpty ? nil : history.reduce(0.0) { $0 + $1.cost }

    return AllStats(
        favoriteModel: favoriteModel,
        activeDaysFraction: activeDaysFraction,
        mostActiveDay: mostActiveDay,
        peakDaySpend: peakDaySpend,
        currentStreak: currentStreak == 0 ? "—" : "\(currentStreak) days",
        longestStreak: longestStreak == 0 ? "—" : "\(longestStreak) days",
        lifetimeTotal: lifetimeTotal,
        historyDayCount: history.count
    )
}

// MARK: - Plan (subscription)

private struct PlanInsight: View {
    @Environment(AppStore.self) private var store
    let usage: SubscriptionUsage?

    private static let fiveHourSeconds: TimeInterval = 5 * 3600
    private static let sevenDaySeconds: TimeInterval = 7 * 86400
    private static let freshWindowThreshold: Double = 0.05

    @State private var projections: [String: WindowProjection] = [:]

    var body: some View {
        Group {
            switch store.subscriptionLoadState {
            case .notBootstrapped, .dormant:
                PlanConnectView(
                    title: "Connect Claude subscription",
                    message: "CodeBurn will read your Claude Code credentials once. macOS will ask permission. After that, the live quota bar shows next to the Claude tab and updates automatically."
                ) { Task { await store.bootstrapSubscription() } }
            case .bootstrapping:
                PlanLoadingView()
            case .loading:
                if let usage {
                    loadedBody(usage: usage)
                } else {
                    PlanLoadingView()
                }
            case .noCredentials:
                PlanNoCredentialsView(
                    title: "No Claude credentials found",
                    message: "Sign in with Claude Code first: open `claude` in your terminal and type `/login`. Then click Try Again."
                ) { Task { await store.bootstrapSubscription() } }
            case .failed:
                PlanFailedView(error: store.subscriptionError)
            case .transientFailure:
                if let usage {
                    loadedBody(usage: usage)
                } else {
                    PlanFailedView(error: store.subscriptionError ?? "Anthropic temporarily unreachable — retrying.")
                }
            case let .terminalFailure(reason):
                PlanReconnectView(
                    title: "Reconnect Claude",
                    reason: reason,
                    fallback: "Your Claude session has expired. Open Claude Code in your terminal and type `/login`, then click Reconnect."
                ) { Task { await store.bootstrapSubscription() } }
            case .loaded:
                if let usage {
                    loadedBody(usage: usage)
                } else {
                    PlanLoadingView()
                }
            }
        }
    }

    @ViewBuilder
    private func loadedBody(usage: SubscriptionUsage) -> some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack(alignment: .firstTextBaseline) {
                Text(usage.tier.displayName)
                    .font(.system(size: 13, weight: .semibold))
                    .foregroundStyle(Theme.brandAccent)
                Spacer()
                if let resets = headlineReset(usage: usage) {
                    Text("Resets \(resets)")
                        .font(.system(size: 10.5))
                        .foregroundStyle(.secondary)
                }
            }

            VStack(spacing: 8) {
                if let p = usage.fiveHourPercent {
                    UtilizationRow(label: "5-hour window", percent: p, resetsAt: usage.fiveHourResetsAt, projection: projections["five_hour"])
                }
                if let p = usage.sevenDayPercent {
                    UtilizationRow(label: "7-day total", percent: p, resetsAt: usage.sevenDayResetsAt, projection: projections["seven_day"])
                }
                if let p = usage.sevenDayOpusPercent {
                    UtilizationRow(label: "7-day Opus", percent: p, resetsAt: usage.sevenDayOpusResetsAt, projection: projections["seven_day_opus"])
                }
                if let p = usage.sevenDaySonnetPercent {
                    UtilizationRow(label: "7-day Sonnet", percent: p, resetsAt: usage.sevenDaySonnetResetsAt, projection: projections["seven_day_sonnet"])
                }
                ForEach(usage.scopedWeekly, id: \.label) { scoped in
                    UtilizationRow(label: "7-day \(scoped.label)", percent: scoped.percent, resetsAt: scoped.resetsAt, projection: projections["scoped_\(scoped.label)"])
                }
            }

            OptimizeSavingsBadge(payload: store.payload)
        }
        .task(id: usage.fetchedAt) {
            await recomputeProjections(usage: usage)
        }
    }

    private func recomputeProjections(usage: SubscriptionUsage) async {
        var result: [String: WindowProjection] = [:]
        var inputs: [(String, Double?, Date?, TimeInterval)] = [
            ("five_hour", usage.fiveHourPercent, usage.fiveHourResetsAt, Self.fiveHourSeconds),
            ("seven_day", usage.sevenDayPercent, usage.sevenDayResetsAt, Self.sevenDaySeconds),
            ("seven_day_opus", usage.sevenDayOpusPercent, usage.sevenDayOpusResetsAt, Self.sevenDaySeconds),
            ("seven_day_sonnet", usage.sevenDaySonnetPercent, usage.sevenDaySonnetResetsAt, Self.sevenDaySeconds),
        ]
        for scoped in usage.scopedWeekly {
            inputs.append(("scoped_\(scoped.label)", scoped.percent, scoped.resetsAt, Self.sevenDaySeconds))
        }
        for (key, percent, resetsAt, windowSeconds) in inputs {
            if let projection = await project(key: key, percent: percent, resetsAt: resetsAt, windowSeconds: windowSeconds) {
                result[key] = projection
            }
        }
        projections = result
    }

    /// Linear extrapolation when window is past the freshness threshold; otherwise falls back to
    /// the prior cycle's final percent from the snapshot store.
    private func project(key: String, percent: Double?, resetsAt: Date?, windowSeconds: TimeInterval) async -> WindowProjection? {
        guard let percent, let resetsAt else { return nil }
        let windowStart = resetsAt.addingTimeInterval(-windowSeconds)
        let elapsed = Date().timeIntervalSince(windowStart)
        let elapsedFraction = elapsed / windowSeconds

        if elapsedFraction > Self.freshWindowThreshold, percent > 0 {
            let projectedPercent = percent / elapsedFraction
            var hitDate: Date? = nil
            if projectedPercent > 100, percent < 100 {
                let remainingPercent = 100 - percent
                let percentPerSecond = percent / elapsed
                if percentPerSecond > 0 {
                    hitDate = Date().addingTimeInterval(remainingPercent / percentPerSecond)
                }
            }
            return WindowProjection(percent: projectedPercent, willOverflow: projectedPercent > 100, hitsLimitAt: hitDate, source: .linear)
        }

        // Window too fresh OR percent exactly zero -- use the prior cycle's final reading.
        if let prior = await SubscriptionSnapshotStore.previousWindowFinal(windowKey: key, currentResetsAt: resetsAt) {
            return WindowProjection(percent: prior, willOverflow: prior > 100, hitsLimitAt: nil, source: .historicalBaseline)
        }
        return nil
    }

    private func headlineReset(usage: SubscriptionUsage) -> String? {
        let candidates = [
            usage.fiveHourResetsAt,
            usage.sevenDayResetsAt,
            usage.sevenDayOpusResetsAt,
            usage.sevenDaySonnetResetsAt,
        ].compactMap { $0 }
        guard let earliest = candidates.min() else { return nil }
        return relativeReset(earliest)
    }
}

// MARK: - Plan empty/loading/failure states

private struct PlanLoadingView: View {
    var body: some View {
        VStack(spacing: 8) {
            ProgressView().scaleEffect(0.8)
            Text("Reading Claude credentials...")
                .font(.system(size: 11, weight: .medium))
                .foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 16)
    }
}

private struct PlanNoCredentialsView: View {
    let title: String
    let message: String
    let onRetry: () -> Void

    var body: some View {
        VStack(spacing: 10) {
            Image(systemName: "key.slash")
                .font(.system(size: 24))
                .foregroundStyle(.tertiary)
            Text(title)
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(.primary)
            Text(.init(message))
                .font(.system(size: 10.5))
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
                .frame(maxWidth: 280)
            Button("Try Again", action: onRetry)
            .controlSize(.small)
            .buttonStyle(.borderedProminent)
            .tint(Theme.brandAccent)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 16)
    }
}

private struct PlanFailedView: View {
    @Environment(AppStore.self) private var store
    let error: String?

    var body: some View {
        VStack(spacing: 8) {
            Image(systemName: "exclamationmark.triangle")
                .font(.system(size: 18))
                .foregroundStyle(Theme.brandAccent)
            Text("Couldn't load plan data")
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(.primary)
            if let error {
                Text(error)
                    .font(.system(size: 10))
                    .foregroundStyle(.tertiary)
                    .multilineTextAlignment(.center)
                    .frame(maxWidth: 280)
                    .lineLimit(3)
            }
            Button("Retry") {
                Task { await store.refreshSubscription() }
            }
            .controlSize(.small)
            .buttonStyle(.borderedProminent)
            .tint(Theme.brandAccent)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 14)
    }
}

/// Shown the very first time a user opens the Plan tab. Clicking Connect is the
/// only path to triggering the provider's credential read (for Claude, the
/// macOS keychain prompt) — the menubar app does not touch credentials at
/// startup.
private struct PlanConnectView: View {
    let title: String
    let message: String
    let onConnect: () -> Void

    var body: some View {
        VStack(spacing: 10) {
            Image(systemName: "link.circle")
                .font(.system(size: 26))
                .foregroundStyle(Theme.brandAccent)
            Text(title)
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(.primary)
            Text(.init(message))
                .font(.system(size: 10.5))
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
                .frame(maxWidth: 280)
            Button("Connect", action: onConnect)
                .controlSize(.small)
                .buttonStyle(.borderedProminent)
                .tint(Theme.brandAccent)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 18)
    }
}

/// Shown when the refresh token has been invalidated (typically because the user
/// re-authenticated on another device). Clicking the button re-runs bootstrap,
/// which reads the provider's credentials source again and writes a fresh copy
/// to our own keychain item.
private struct PlanReconnectView: View {
    let title: String
    let reason: String?
    let fallback: String
    let onReconnect: () -> Void

    var body: some View {
        VStack(spacing: 10) {
            Image(systemName: "arrow.triangle.2.circlepath.circle")
                .font(.system(size: 24))
                .foregroundStyle(.red)
            Text(title)
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(.primary)
            Text(reason ?? fallback)
                .font(.system(size: 10.5))
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
                .frame(maxWidth: 280)
                .lineLimit(3)
            Button("Reconnect", action: onReconnect)
                .controlSize(.small)
                .buttonStyle(.borderedProminent)
                .tint(.red)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 16)
    }
}

/// Plan tab for Codex. Mirrors PlanInsight's layout but reads from
/// store.codexUsage / store.codexLoadState. We deliberately skip the
/// "On pace at reset" projection here — that math is fed by local
/// per-message Claude spend extrapolated against the API quota windows;
/// our local Codex spend isn't an apples-to-apples signal for the
/// ChatGPT-subscription rate windows reported by wham/usage. Add when
/// we wire a comparable extrapolator.
private struct CodexPlanInsight: View {
    @Environment(AppStore.self) private var store

    var body: some View {
        Group {
            switch store.codexLoadState {
            case .notBootstrapped, .dormant:
                PlanConnectView(
                    title: "Connect ChatGPT subscription",
                    message: "CodeBurn will read your Codex CLI credentials once. After that, the live quota bar shows next to the Codex tab and updates automatically."
                ) { Task { await store.bootstrapCodex() } }
            case .bootstrapping:
                PlanLoadingView()
            case .loading:
                if let usage = store.codexUsage {
                    loadedBody(usage: usage)
                } else {
                    PlanLoadingView()
                }
            case .noCredentials:
                PlanNoCredentialsView(
                    title: "No Codex credentials found",
                    message: "Sign in with Codex first: run `codex login` in your terminal. Then click Try Again."
                ) { Task { await store.bootstrapCodex() } }
            case .failed:
                PlanFailedView(error: store.codexError)
            case .transientFailure:
                if let usage = store.codexUsage {
                    loadedBody(usage: usage)
                } else {
                    PlanFailedView(error: store.codexError ?? "ChatGPT temporarily unreachable — retrying.")
                }
            case let .terminalFailure(reason):
                PlanReconnectView(
                    title: "Reconnect Codex",
                    reason: reason,
                    fallback: "Your ChatGPT session has expired. Run `codex login` in your terminal, then click Reconnect."
                ) { Task { await store.bootstrapCodex() } }
            case .loaded:
                if let usage = store.codexUsage {
                    loadedBody(usage: usage)
                } else {
                    PlanLoadingView()
                }
            }
        }
    }

    @ViewBuilder
    private func loadedBody(usage: CodexUsage) -> some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack(alignment: .firstTextBaseline) {
                Text(usage.plan.displayName)
                    .font(.system(size: 13, weight: .semibold))
                    .foregroundStyle(.primary)
                Spacer()
                if let resetsAt = (usage.primary ?? usage.secondary)?.resetsAt {
                    Text("Resets \(relativeReset(resetsAt))")
                        .font(.system(size: 10.5))
                        .foregroundStyle(.secondary)
                }
            }
            if let primary = usage.primary {
                UtilizationRow(
                    label: "\(primary.windowLabel) window",
                    percent: primary.usedPercent,
                    resetsAt: primary.resetsAt,
                    projection: nil
                )
            }
            if let secondary = usage.secondary {
                UtilizationRow(
                    label: "\(secondary.windowLabel) window",
                    percent: secondary.usedPercent,
                    resetsAt: secondary.resetsAt,
                    projection: nil
                )
            }
            // Surface non-zero per-model rate limits (Codex Spark, etc.) so
            // power users see them; idle ones stay collapsed.
            ForEach(Array(usage.additionalLimits.enumerated()), id: \.offset) { _, limit in
                if let p = limit.primary, p.usedPercent > 0 {
                    UtilizationRow(
                        label: "\(limit.name) · \(p.windowLabel)",
                        percent: p.usedPercent,
                        resetsAt: p.resetsAt,
                        projection: nil
                    )
                }
                if let s = limit.secondary, s.usedPercent > 0 {
                    UtilizationRow(
                        label: "\(limit.name) · \(s.windowLabel)",
                        percent: s.usedPercent,
                        resetsAt: s.resetsAt,
                        projection: nil
                    )
                }
            }
        }
        .padding(.horizontal, 14)
        .padding(.top, 4)
        .padding(.bottom, 8)
    }

    private func relativeReset(_ date: Date) -> String {
        let f = RelativeDateTimeFormatter()
        f.unitsStyle = .short
        return f.localizedString(for: date, relativeTo: Date())
    }
}

private struct WindowProjection {
    enum Source { case linear, historicalBaseline }
    let percent: Double
    let willOverflow: Bool
    let hitsLimitAt: Date?
    let source: Source
}

private struct UtilizationRow: View {
    let label: String
    /// API returns utilization as 0..100 (a percentage value, not a fraction).
    let percent: Double
    let resetsAt: Date?
    let projection: WindowProjection?

    var body: some View {
        VStack(spacing: 3) {
            HStack(alignment: .firstTextBaseline) {
                Text(label)
                    .font(.system(size: 11, weight: .medium))
                    .foregroundStyle(.secondary)
                Spacer()
                Text(String(format: "%.0f%%", clampedPercent))
                    .font(.codeMono(size: 11, weight: .semibold))
                    .foregroundStyle(barColor)
                    .monospacedDigit()
            }
            UtilizationBar(
                fraction: clampedPercent / 100,
                color: barColor,
                markerFraction: projection.map { min(max($0.percent, 0), 100) / 100 }
            )
            .frame(height: 6)
            if let projection {
                ProjectionCaption(projection: projection)
            }
        }
    }

    private var clampedPercent: Double { min(max(percent, 0), 100) }

    /// Single-color brand palette decision (see session notes): the number is the signal, not
    /// the color. Keeping this as a computed property so a future threshold-based palette
    /// reintroduction stays scoped to one place.
    private var barColor: Color { Theme.brandAccent }
}

private struct ProjectionCaption: View {
    let projection: WindowProjection

    var body: some View {
        HStack(spacing: 3) {
            if projection.willOverflow {
                Image(systemName: "exclamationmark.triangle.fill")
                    .font(.system(size: 8, weight: .bold))
                    .foregroundStyle(Theme.brandAccent)
            } else {
                Image(systemName: "arrow.up.right")
                    .font(.system(size: 8, weight: .bold))
                    .foregroundStyle(.tertiary)
            }
            Text(captionText)
                .font(.system(size: 9.5, weight: .medium))
                .foregroundStyle(projection.willOverflow
                    ? AnyShapeStyle(Theme.brandAccent)
                    : AnyShapeStyle(.tertiary))
            Spacer()
        }
    }

    private var captionText: String {
        let projected = String(format: "%.0f%%", projection.percent)
        switch projection.source {
        case .linear:
            if projection.willOverflow, let hit = projection.hitsLimitAt {
                return "On pace: \(projected) at reset · hits 100% \(relativeReset(hit))"
            }
            return "On pace: \(projected) at reset"
        case .historicalBaseline:
            return "Based on last cycle: \(projected)"
        }
    }
}

private struct UtilizationBar: View {
    /// 0..1 fraction of the bar to fill.
    let fraction: Double
    let color: Color
    /// Optional 0..1 marker position for projected utilization at reset.
    let markerFraction: Double?

    var body: some View {
        GeometryReader { geo in
            ZStack(alignment: .leading) {
                RoundedRectangle(cornerRadius: 3).fill(Color.secondary.opacity(0.12))
                RoundedRectangle(cornerRadius: 3)
                    .fill(color)
                    .frame(width: max(0, geo.size.width * CGFloat(fraction)))
                if let m = markerFraction {
                    Rectangle()
                        .fill(Color.primary.opacity(0.55))
                        .frame(width: 1.5)
                        .offset(x: max(0, geo.size.width * CGFloat(m)) - 0.75)
                }
            }
        }
    }
}

private func relativeReset(_ date: Date) -> String {
    let interval = date.timeIntervalSinceNow
    if interval <= 0 { return "now" }
    let hours = interval / 3600
    if hours < 1 {
        let minutes = Int(ceil(interval / 60))
        return "in \(minutes)m"
    }
    if hours < 24 { return "in \(Int(ceil(hours)))h" }
    let days = Int(ceil(hours / 24))
    return "in \(days)d"
}
