import SwiftUI
import Charts

struct ChartsContainerView: View {
    @EnvironmentObject var accountStore: AccountStore
    @StateObject private var viewModel: ChartsViewModel
    @StateObject private var goalsViewModel = GoalsViewModel()
    @AppStorage("showForecast") private var showForecast = true
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass

    init(iapService: IAPService) {
        _viewModel = StateObject(wrappedValue: ChartsViewModel(iapService: iapService))
    }

    var body: some View {
        NavigationStack {
            Group {
                if horizontalSizeClass == .regular {
                    iPadChartsLayout
                } else {
                    iPhoneChartsLayout
                }
            }
            .navigationTitle("Charts")
            .sheet(isPresented: $viewModel.showingPaywall) { PaywallView() }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) { accountFilterMenu }
            }
            .onAppear { syncState() }
            .onChange(of: accountStore.selectedAccount) { _, newAccount in
                viewModel.selectedAccount = newAccount
                goalsViewModel.selectedAccount = newAccount
                goalsViewModel.refresh()
                viewModel.updatePredictionTargetDate(goalsViewModel.goals)
            }
            .onChange(of: accountStore.showAllAccounts) { _, showAll in
                viewModel.showAllAccounts = showAll
                goalsViewModel.showAllAccounts = showAll
                goalsViewModel.refresh()
                viewModel.updatePredictionTargetDate(goalsViewModel.goals)
            }
            .onChange(of: goalsViewModel.goals) { _, goals in
                viewModel.updatePredictionTargetDate(goals)
            }
        }
    }

    // MARK: - iPad Layout (sidebar + full-width chart)

    private var iPadChartsLayout: some View {
        HStack(spacing: 0) {
            // Left sidebar: grouped chart-type tiles + contextual filters
            ScrollView {
                VStack(alignment: .leading, spacing: 0) {
                    ForEach(Self.chartGroups, id: \.titleKey) { group in
                        let types = group.types.filter { showForecast || $0 != .prediction }
                        if !types.isEmpty {
                            Text(String(localized: String.LocalizationValue(group.titleKey)))
                                .font(.caption.weight(.semibold))
                                .foregroundColor(.secondary)
                                .padding(.horizontal, 16)
                                .padding(.top, 14)
                                .padding(.bottom, 6)

                            LazyVGrid(columns: [GridItem(.flexible(), spacing: 8), GridItem(.flexible())], spacing: 8) {
                                ForEach(types) { chartType in
                                    iPadChartTypeTile(chartType)
                                }
                            }
                            .padding(.horizontal, 12)
                        }
                    }

                    if hasAnyFilter {
                        Divider().padding(.vertical, 12)
                        filtersSection
                            .padding(.horizontal, 16)
                            .padding(.bottom, 16)
                    } else {
                        Spacer().frame(height: 16)
                    }
                }
            }
            .frame(width: 248)
            .background(Color(.systemBackground))

            Divider()

            // Right panel: KPI header + period control + chart
            ZStack {
                AppBackground()
                ScrollView {
                    VStack(spacing: 16) {
                        kpiHeader

                        chartToolbar

                        if !viewModel.isPremium {
                            CompactPaywallBanner(showingPaywall: $viewModel.showingPaywall)
                                .onAppear {
                                    FirebaseService.shared.logPaywallShown(trigger: "charts_banner")
                                }
                        }
                        chartContent
                        if viewModel.hiddenHistoryMonths > 0 {
                            lockedHistoryTeaser
                        }
                    }
                    .padding()
                }
            }
        }
        .ignoresSafeArea(edges: .bottom)
    }

    // MARK: - Chart groups (sidebar sections)

    private static let chartGroups: [(titleKey: String, types: [ChartsViewModel.ChartType])] = [
        ("chart_group_overview", [.evolution, .allocation, .performance, .contributions]),
        ("chart_group_analyze", [.comparison, .periodComparison, .yearOverYear, .rollingReturn]),
        ("chart_group_risk", [.drawdown, .volatility, .riskReturn, .cashflow]),
        ("chart_group_forecast", [.prediction, .simulator])
    ]

    // MARK: - KPI Header (iPad)

    /// Portfolio-level metrics for the active time range, always visible above the chart.
    private var kpiHeader: some View {
        let m = viewModel.portfolioMetrics
        return HStack(spacing: 10) {
            kpiCard(label: String(localized: "kpi_total_value"), value: m.formattedTotalValue, color: .primary)
            kpiCard(label: String(localized: "kpi_period_return"), value: m.formattedPercentageReturn,
                    color: m.percentageReturn >= 0 ? .positiveGreen : .negativeRed)
            kpiCard(label: String(localized: "kpi_cagr"), value: m.formattedCAGR,
                    color: m.cagr >= 0 ? .positiveGreen : .negativeRed)
            kpiCard(label: String(localized: "kpi_volatility"), value: m.formattedVolatility, color: .primary)
            kpiCard(label: String(localized: "kpi_max_drawdown"), value: m.formattedMaxDrawdown, color: .negativeRed)
        }
    }

    private func kpiCard(label: String, value: String, color: Color) -> some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(label)
                .font(.caption)
                .foregroundColor(.secondary)
                .lineLimit(1)
                .minimumScaleFactor(0.8)
            Text(value)
                .font(.system(.title3, design: .rounded).weight(.semibold))
                .foregroundColor(color)
                .lineLimit(1)
                .minimumScaleFactor(0.6)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(12)
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.smallCornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 4, y: 1)
    }

    // MARK: - Chart toolbar (iPad): title + native segmented period picker

    @ViewBuilder
    private var chartToolbar: some View {
        let ranges = viewModel.availableTimeRanges(for: viewModel.selectedChartType)
        HStack(spacing: 12) {
            VStack(alignment: .leading, spacing: 2) {
                Text(viewModel.selectedChartType.rawValue)
                    .font(.headline)
                Text(viewModel.selectedChartType.description)
                    .font(.caption)
                    .foregroundColor(.secondary)
                    .lineLimit(1)
            }
            Spacer()
            if !ranges.isEmpty && viewModel.selectedChartType != .performance {
                Picker("Period", selection: $viewModel.selectedTimeRange) {
                    ForEach(ranges) { range in
                        Text(range.rawValue).tag(range)
                    }
                }
                .pickerStyle(.segmented)
                .frame(maxWidth: 360)
            }
        }
        .padding(.horizontal, 4)
    }

    /// Concrete loss-framing upsell: the user has real data older than the free
    /// 12-month window; tell them exactly how much is locked instead of hiding it.
    private var lockedHistoryTeaser: some View {
        Button {
            FirebaseService.shared.logPaywallShown(trigger: "history_teaser")
            viewModel.showingPaywall = true
        } label: {
            HStack(spacing: 8) {
                Image(systemName: "lock.fill")
                Text(String(format: String(localized: "chart_history_locked"), viewModel.hiddenHistoryMonths))
                    .multilineTextAlignment(.leading)
                Spacer()
                Image(systemName: "chevron.right")
                    .font(.caption)
            }
            .font(.footnote.weight(.medium))
            .foregroundColor(.appPrimary)
            .padding(12)
            .background(Color.appPrimary.opacity(0.08))
            .cornerRadius(AppConstants.UI.smallCornerRadius)
        }
        .buttonStyle(.plain)
    }

    // MARK: - iPhone Layout

    private var iPhoneChartsLayout: some View {
        ZStack {
            AppBackground()
            ScrollView {
                VStack(spacing: 20) {
                    chartTypeSelector
                    if !viewModel.isPremium {
                        CompactPaywallBanner(showingPaywall: $viewModel.showingPaywall)
                            .onAppear {
                                FirebaseService.shared.logPaywallShown(trigger: "charts_banner")
                            }
                    }
                    filtersSection
                    chartContent
                    if viewModel.hiddenHistoryMonths > 0 {
                        lockedHistoryTeaser
                    }
                }
                .padding()
            }
        }
    }

    // MARK: - iPad Chart Type Tile

    private func iPadChartTypeTile(_ chartType: ChartsViewModel.ChartType) -> some View {
        let isSelected = viewModel.selectedChartType == chartType
        let isPremiumLocked = chartType.isPremium && !viewModel.isPremium
        return Button {
            viewModel.selectChart(chartType)
        } label: {
            VStack(spacing: 6) {
                ZStack(alignment: .topTrailing) {
                    Image(systemName: chartType.icon)
                        .font(.system(size: 18))
                        .foregroundColor(isSelected ? .white : .appPrimary)
                        .frame(maxWidth: .infinity)
                        .frame(height: 34)
                    if isPremiumLocked {
                        Image(systemName: "lock.fill")
                            .font(.system(size: 9))
                            .foregroundColor(isSelected ? .white.opacity(0.8) : .secondary)
                    }
                }
                Text(chartType.rawValue)
                    .font(.caption2.weight(isSelected ? .semibold : .regular))
                    .foregroundColor(isSelected ? .white : .primary)
                    .lineLimit(2)
                    .multilineTextAlignment(.center)
                    .minimumScaleFactor(0.8)
                    .frame(height: 26, alignment: .top)
            }
            .padding(.vertical, 8)
            .padding(.horizontal, 4)
            .frame(maxWidth: .infinity)
            .background(isSelected ? Color.appPrimary : Color(.systemGray6))
            .cornerRadius(10)
        }
        .buttonStyle(.plain)
        .accessibilityLabel(chartType.rawValue)
        .accessibilityAddTraits(isSelected ? [.isSelected] : [])
    }

    // MARK: - Shared

    private func syncState() {
        viewModel.selectedAccount = accountStore.selectedAccount
        viewModel.showAllAccounts = accountStore.showAllAccounts
        viewModel.loadData()
        goalsViewModel.selectedAccount = accountStore.selectedAccount
        goalsViewModel.showAllAccounts = accountStore.showAllAccounts
        goalsViewModel.refresh()
        viewModel.updatePredictionTargetDate(goalsViewModel.goals)
    }

    // MARK: - Chart Type Selector

    private var chartTypeSelector: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 12) {
                ForEach(viewModel.availableChartTypes.filter { showForecast || $0 != .prediction }) { chartType in
                    ChartTypeButton(
                        chartType: chartType,
                        isSelected: viewModel.selectedChartType == chartType,
                        isPremium: chartType.isPremium,
                        userIsPremium: viewModel.isPremium
                    ) {
                        viewModel.selectChart(chartType)
                    }
                }
            }
            .padding(.horizontal, 4)
        }
    }

    // MARK: - Unified Filters Section

    private var hasAnyFilter: Bool {
        let chartType = viewModel.selectedChartType
        let isPad = horizontalSizeClass == .regular
        // These chart types manage their own controls internally, no external filter bar needed
        if chartType == .comparison || chartType == .simulator || chartType == .periodComparison {
            // On iPad the period picker lives in the chart toolbar, not the filter bar.
            return isPad ? false : !viewModel.availableTimeRanges(for: chartType).isEmpty
        }
        let hasTimeRange = !isPad && chartType != .allocation && chartType != .riskReturn
        let hasCategories = !viewModel.availableCategories(for: chartType).isEmpty
        let hasSources = !viewModel.availableSources(for: chartType).isEmpty
        let hasBreakdown = chartType == .allocation || chartType == .performance
        return hasTimeRange || hasCategories || hasSources || hasBreakdown
    }

    @ViewBuilder
    private var filtersSection: some View {
        if hasAnyFilter {
            VStack(alignment: .leading, spacing: 10) {
                let chartType = viewModel.selectedChartType

                // Time Range (not for performance — uses slider). On iPad the period
                // picker lives in the chart toolbar, not the sidebar.
                if horizontalSizeClass != .regular
                    && chartType != .allocation && chartType != .riskReturn && chartType != .performance {
                    filterRow(icon: "calendar", label: "Period") {
                        timeRangeSelector
                    }
                }

                // Performance: custom period slider
                if chartType == .performance {
                    filterRow(icon: "calendar.badge.clock", label: "Period: \(periodLabel(viewModel.performancePeriodMonths))") {
                        Slider(
                            value: Binding(
                                get: { Double(viewModel.performancePeriodMonths) },
                                set: { viewModel.performancePeriodMonths = Int($0) }
                            ),
                            in: 1...60,
                            step: 1
                        )
                        .tint(.appPrimary)
                    }
                }

                // Breakdown (category vs source)
                if chartType == .allocation || chartType == .performance {
                    filterRow(icon: "square.grid.2x2", label: "Group") {
                        breakdownSelector
                    }
                }

                // Category
                let availableCategories = viewModel.availableCategories(for: chartType)
                if !availableCategories.isEmpty {
                    filterRow(icon: "tag", label: "Category") {
                        categoryFilter
                    }
                }

                // Source
                let availableSources = viewModel.availableSources(for: chartType)
                if !availableSources.isEmpty {
                    filterRow(icon: "building.2", label: "Source") {
                        sourceFilter
                    }
                }
            }
            .padding(12)
            .background(Color(.systemBackground))
            .cornerRadius(AppConstants.UI.cornerRadius)
            .shadow(color: .black.opacity(0.05), radius: 4, y: 1)
        }
    }

    private func filterRow<Content: View>(icon: String, label: String, @ViewBuilder content: () -> Content) -> some View {
        VStack(alignment: .leading, spacing: 6) {
            HStack(spacing: 4) {
                Image(systemName: icon)
                    .font(.caption2)
                    .foregroundColor(.secondary)
                Text(label)
                    .font(.caption.weight(.medium))
                    .foregroundColor(.secondary)
            }
            content()
        }
    }

    // MARK: - Time Range Selector

    private var timeRangeSelector: some View {
        Group {
            if horizontalSizeClass == .regular {
                LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 6) {
                    ForEach(viewModel.availableTimeRanges(for: viewModel.selectedChartType)) { range in
                        timeRangeButton(range, fullWidth: true)
                    }
                }
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(viewModel.availableTimeRanges(for: viewModel.selectedChartType)) { range in
                            timeRangeButton(range, fullWidth: false)
                        }
                    }
                }
            }
        }
    }

    private func timeRangeButton(_ range: ChartsViewModel.TimeRange, fullWidth: Bool) -> some View {
        Button {
            viewModel.selectedTimeRange = range
        } label: {
            Text(range.rawValue)
                .font(.subheadline.weight(.medium))
                .frame(maxWidth: fullWidth ? .infinity : nil)
                .padding(.horizontal, fullWidth ? 8 : 16)
                .padding(.vertical, 8)
                .background(viewModel.selectedTimeRange == range ? Color.appPrimary : Color.gray.opacity(0.1))
                .foregroundColor(viewModel.selectedTimeRange == range ? .white : .primary)
                .cornerRadius(20)
        }
    }

    // MARK: - Category Filter

    @ViewBuilder
    private var categoryFilter: some View {
        let availableCategories = viewModel.availableCategories(for: viewModel.selectedChartType)
        if !availableCategories.isEmpty {
            if horizontalSizeClass == .regular {
                VStack(spacing: 4) {
                    if availableCategories.count > 1 {
                        categoryPill(label: "All", color: .appPrimary, isSelected: viewModel.selectedCategory == nil) {
                            viewModel.selectedCategory = nil
                        }
                    }
                    ForEach(availableCategories) { category in
                        categoryPill(label: category.name, color: category.color,
                                     isSelected: viewModel.selectedCategory?.id == category.id) {
                            viewModel.selectedCategory = category
                            viewModel.selectedSource = nil
                        }
                    }
                }
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        if availableCategories.count > 1 {
                            categoryPill(label: "All", color: .appPrimary,
                                         isSelected: viewModel.selectedCategory == nil) {
                                viewModel.selectedCategory = nil
                            }
                        }
                        ForEach(availableCategories) { category in
                            categoryPill(label: category.name, color: category.color,
                                         isSelected: viewModel.selectedCategory?.id == category.id) {
                                viewModel.selectedCategory = category
                                viewModel.selectedSource = nil
                            }
                        }
                    }
                }
            }
        }
    }

    private func categoryPill(label: String, color: Color, isSelected: Bool, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Text(label)
                .font(.caption.weight(.medium))
                .frame(maxWidth: horizontalSizeClass == .regular ? .infinity : nil)
                .padding(.horizontal, 12)
                .padding(.vertical, 6)
                .background(isSelected ? color : Color.gray.opacity(0.1))
                .foregroundColor(isSelected ? .white : .primary)
                .cornerRadius(16)
        }
    }

    // MARK: - Source Filter

    @ViewBuilder
    private var sourceFilter: some View {
        let availableSources = viewModel.availableSources(for: viewModel.selectedChartType)
        if !availableSources.isEmpty {
            if horizontalSizeClass == .regular {
                VStack(spacing: 4) {
                    if availableSources.count > 1 {
                        sourcePill(label: "All Sources", color: .appPrimary,
                                   isSelected: viewModel.selectedSourceIds.isEmpty && viewModel.selectedSource == nil) {
                            viewModel.selectedSource = nil
                            viewModel.selectedSourceIds.removeAll()
                        }
                    }
                    ForEach(Array(availableSources.enumerated()), id: \.element.id) { index, source in
                        let isSelected = viewModel.selectedSourceIds.contains(source.id)
                        sourcePill(label: source.name, color: Color.sourceColor(at: index), isSelected: isSelected) {
                            viewModel.selectedSource = nil
                            if isSelected { viewModel.selectedSourceIds.remove(source.id) }
                            else { viewModel.selectedSourceIds.insert(source.id) }
                        }
                    }
                }
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        if availableSources.count > 1 {
                            sourcePill(label: "All Sources", color: .appPrimary,
                                       isSelected: viewModel.selectedSourceIds.isEmpty && viewModel.selectedSource == nil) {
                                viewModel.selectedSource = nil
                                viewModel.selectedSourceIds.removeAll()
                            }
                        }
                        ForEach(Array(availableSources.enumerated()), id: \.element.id) { index, source in
                            let isSelected = viewModel.selectedSourceIds.contains(source.id)
                            sourcePill(label: source.name, color: Color.sourceColor(at: index), isSelected: isSelected) {
                                viewModel.selectedSource = nil
                                if isSelected { viewModel.selectedSourceIds.remove(source.id) }
                                else { viewModel.selectedSourceIds.insert(source.id) }
                            }
                        }
                    }
                }
            }
        }
    }

    private func sourcePill(label: String, color: Color, isSelected: Bool, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Text(label)
                .font(.caption.weight(.medium))
                .frame(maxWidth: horizontalSizeClass == .regular ? .infinity : nil)
                .padding(.horizontal, 12)
                .padding(.vertical, 6)
                .background(isSelected ? color : Color.gray.opacity(0.1))
                .foregroundColor(isSelected ? .white : .primary)
                .cornerRadius(16)
        }
    }

    // MARK: - Breakdown Selector

    private var breakdownSelector: some View {
        Group {
            if horizontalSizeClass == .regular {
                VStack(spacing: 4) {
                    ForEach(ChartsViewModel.BreakdownMode.allCases) { mode in
                        breakdownButton(mode)
                    }
                }
            } else {
                HStack(spacing: 8) {
                    ForEach(ChartsViewModel.BreakdownMode.allCases) { mode in
                        breakdownButton(mode)
                    }
                }
            }
        }
    }

    private func breakdownButton(_ mode: ChartsViewModel.BreakdownMode) -> some View {
        Button {
            viewModel.selectedBreakdown = mode
        } label: {
            Text(mode.rawValue)
                .font(.subheadline.weight(.medium))
                .frame(maxWidth: horizontalSizeClass == .regular ? .infinity : nil)
                .padding(.horizontal, 14)
                .padding(.vertical, 8)
                .background(viewModel.selectedBreakdown == mode ? Color.appPrimary : Color.gray.opacity(0.1))
                .foregroundColor(viewModel.selectedBreakdown == mode ? .white : .primary)
                .cornerRadius(18)
        }
    }

    private func periodLabel(_ months: Int) -> String {
        if months < 12 {
            return "\(months)M"
        } else if months % 12 == 0 {
            return "\(months / 12)Y"
        } else {
            return "\(months / 12)Y \(months % 12)M"
        }
    }

    // MARK: - Chart Content

    @ViewBuilder
    private var chartContent: some View {
        if viewModel.isLoading {
            ProgressView()
                .frame(height: 300)
        } else if !viewModel.hasData {
            emptyStateView
        } else {
            switch viewModel.selectedChartType {
            case .evolution:
                EvolutionChartView(
                    data: viewModel.evolutionData,
                    categoryData: viewModel.categoryEvolutionData,
                    goals: goalsViewModel.goals
                )
            case .allocation:
                VStack(spacing: 20) {
                    AllocationPieChart(
                        data: viewModel.allocationData,
                        title: viewModel.selectedBreakdown == .source ? "Allocation by Source" : "Asset Allocation",
                        showsTargetsComparison: ChartsViewModel.supportsAllocationTargets(for: viewModel.selectedBreakdown)
                    )

                    if !viewModel.allocationEvolutionData.isEmpty {
                        AllocationEvolutionChart(data: viewModel.allocationEvolutionData)
                    }
                }
            case .performance:
                PerformanceBarChart(
                    data: viewModel.performanceData,
                    title: viewModel.selectedBreakdown == .source ? "Performance by Source" : "Performance by Category"
                )
            case .contributions:
                ContributionsChartView(data: viewModel.contributionsData)
            case .rollingReturn:
                RollingReturnChartView(data: viewModel.rollingReturnData)
            case .riskReturn:
                RiskReturnChartView(data: viewModel.riskReturnData)
            case .cashflow:
                CashflowStackedChartView(data: viewModel.cashflowData)
            case .drawdown:
                DrawdownChart(data: viewModel.drawdownData)
            case .volatility:
                VolatilityChartView(data: viewModel.volatilityData)
            case .prediction:
                PredictionChartView(
                    predictions: viewModel.predictionData,
                    historicalData: viewModel.evolutionData
                )
            case .yearOverYear:
                YearOverYearChartView(viewModel: viewModel)
            case .comparison:
                ComparisonChartView(viewModel: viewModel)
            case .simulator:
                AllocationSimulatorView(viewModel: viewModel)
            case .periodComparison:
                PeriodComparisonChartView(viewModel: viewModel)
            }
        }
    }

    private var emptyStateView: some View {
        VStack(spacing: 16) {
            Image(systemName: "chart.bar.xaxis")
                .font(.system(size: 48))
                .foregroundColor(.secondary)

            Text("No Data Available")
                .font(.headline)

            Text("Add some investment sources and snapshots to see charts.")
                .font(.subheadline)
                .foregroundColor(.secondary)
                .multilineTextAlignment(.center)
        }
        .frame(height: 300)
    }

    private var accountFilterMenu: some View {
        Menu {
            Button {
                accountStore.selectAllAccounts()
            } label: {
                HStack {
                    Text("All Accounts")
                    if accountStore.showAllAccounts {
                        Image(systemName: "checkmark")
                    }
                }
            }

            Divider()

            ForEach(availableAccounts, id: \.objectID) { account in
                Button {
                    accountStore.selectAccount(account)
                } label: {
                    HStack {
                        Text(account.name)
                        if accountStore.selectedAccount?.safeId == account.safeId && !accountStore.showAllAccounts {
                            Image(systemName: "checkmark")
                        }
                    }
                }
            }
        } label: {
            Image(systemName: "person.2.circle")
        }
    }

    private var availableAccounts: [Account] {
        accountStore.accounts.filter { $0.safeId != nil }
    }
}

// MARK: - Chart Type Button

struct ChartTypeButton: View {
    let chartType: ChartsViewModel.ChartType
    let isSelected: Bool
    let isPremium: Bool
    let userIsPremium: Bool
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            VStack(spacing: 8) {
                ZStack(alignment: .topTrailing) {
                    Image(systemName: chartType.icon)
                        .font(.title2)

                    if isPremium && !userIsPremium {
                        Image(systemName: "lock.fill")
                            .font(.caption2)
                            .foregroundColor(.appWarning)
                            .offset(x: 8, y: -4)
                    }
                }

                Text(chartType.rawValue)
                    .font(.caption)
            }
            .frame(width: 80, height: 70)
            .background(
                isSelected
                    ? LinearGradient.appPrimaryGradient
                    : LinearGradient(
                        colors: [
                            Color(.systemBackground).opacity(0.85),
                            Color(.systemBackground).opacity(0.85)
                        ],
                        startPoint: .top,
                        endPoint: .bottom
                    )
            )
            .foregroundColor(isSelected ? .white : .primary)
            .cornerRadius(AppConstants.UI.cornerRadius)
            .shadow(color: .black.opacity(0.05), radius: 4, y: 2)
        }
    }
}

// MARK: - Evolution Chart View

struct EvolutionChartView: View {
    let data: [(date: Date, value: Decimal)]
    @State private var zoom = ChartZoomModel()
    let categoryData: [CategoryEvolutionPoint]
    let goals: [Goal]

    @State private var selectedDataPoint: (date: Date, value: Decimal)?
    @State private var chartMode: ChartMode = .total
    @State private var showGoalLines = false

    enum ChartMode: String, CaseIterable, Identifiable {
        case total = "Total"
        case byCategory = "By Category"

        var id: String { rawValue }
    }

    private static let compactXAxisDateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = .autoupdatingCurrent
        formatter.setLocalizedDateFormatFromTemplate("MMM yy")
        return formatter
    }()

    private var xAxisMonthStride: Int {
        switch data.count {
        case ...8:
            return 1
        case ...16:
            return 2
        case ...30:
            return 3
        case ...48:
            return 4
        default:
            return 6
        }
    }

    private var stackedCategoryData: [CategoryEvolutionPoint] {
        guard !categoryData.isEmpty else { return [] }

        let totalsByCategory = categoryData.reduce(into: [String: Decimal]()) { result, point in
            result[point.categoryName, default: 0] += point.value
        }

        let categoryOrder = totalsByCategory
            .sorted { $0.value > $1.value }
            .map { $0.key }
        let orderIndex = Dictionary(uniqueKeysWithValues: categoryOrder.enumerated().map { ($0.element, $0.offset) })

        let groupedByDate = Dictionary(grouping: categoryData) { $0.date }
        let sortedDates = groupedByDate.keys.sorted()

        var stacked: [CategoryEvolutionPoint] = []

        for date in sortedDates {
            guard let points = groupedByDate[date] else { continue }
            let sortedPoints = points.sorted {
                (orderIndex[$0.categoryName] ?? Int.max) < (orderIndex[$1.categoryName] ?? Int.max)
            }

            var running: Decimal = 0
            for point in sortedPoints {
                running += point.value
                stacked.append(CategoryEvolutionPoint(
                    date: point.date,
                    categoryName: point.categoryName,
                    colorHex: point.colorHex,
                    value: running
                ))
            }
        }

        return stacked
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            headerView
            modePicker
            chartSection
            if !data.isEmpty && chartMode == .total {
                ChartStatsRow(stats: evolutionStats)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var evolutionStats: [ChartStat] {
        guard !data.isEmpty else { return [] }
        let values = data.map { NSDecimalNumber(decimal: $0.value).doubleValue }
        let latest = values.last ?? 0
        let first = values.first ?? 0
        let change = latest - first
        let changePct = first > 0 ? (change / first) * 100 : 0
        let maxVal = values.max() ?? 0
        let minVal = values.min() ?? 0
        return [
            ChartStat(label: "Latest", value: Decimal(latest).compactCurrencyString, color: .appPrimary),
            ChartStat(label: "Change", value: String(format: "%+.1f%%", changePct), color: changePct >= 0 ? .positiveGreen : .negativeRed),
            ChartStat(label: "Max", value: Decimal(maxVal).compactCurrencyString, color: .positiveGreen),
            ChartStat(label: "Min", value: Decimal(minVal).compactCurrencyString, color: .negativeRed),
        ]
    }

    private var headerView: some View {
        HStack {
            Text("Portfolio Evolution")
                .font(.headline)

            Spacer()

            if let selected = selectedDataPoint, chartMode == .total {
                VStack(alignment: .trailing, spacing: 2) {
                    Text(selected.value.compactCurrencyString)
                        .font(.subheadline.weight(.semibold))
                    Text(selected.date.monthYearString)
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            }

            Button {
                showGoalLines.toggle()
            } label: {
                Image(systemName: showGoalLines ? "target" : "slash.circle")
                    .foregroundColor(.secondary)
            }
            .disabled(goals.isEmpty)
            .accessibilityLabel(showGoalLines ? "Hide goals" : "Show goals")
        }
    }

    private var modePicker: some View {
        Picker("Evolution Mode", selection: $chartMode) {
            ForEach(ChartMode.allCases) { mode in
                Text(mode.rawValue).tag(mode)
            }
        }
        .pickerStyle(.segmented)
    }

    @ViewBuilder
    private var chartSection: some View {
        if data.count >= 2 {
            chartView
        } else {
            Text("Not enough data")
                .foregroundColor(.secondary)
                .frame(height: 300)
        }
    }

    private var chartView: some View {
        Chart {
            chartMarks
        }
        .chartForegroundStyleScale(domain: chartCategoryNames, range: chartCategoryColors)
        .chartXAxis {
            AxisMarks(values: .stride(by: .month, count: xAxisMonthStride)) { value in
                AxisGridLine(stroke: StrokeStyle(lineWidth: 0.8, dash: [3, 3]))
                    .foregroundStyle(Color.secondary.opacity(0.2))
                AxisTick(stroke: StrokeStyle(lineWidth: 0.8))
                    .foregroundStyle(Color.secondary.opacity(0.28))
                AxisValueLabel {
                    if let date = value.as(Date.self) {
                        Text(date, formatter: Self.compactXAxisDateFormatter)
                            .font(.caption2)
                    }
                }
            }
        }
        .chartYAxis {
            AxisMarks(position: .leading) { value in
                AxisValueLabel {
                    if let doubleValue = value.as(Double.self) {
                        Text(Decimal(doubleValue).shortCurrencyString)
                            .font(.caption)
                    }
                }
            }
        }
        .chartOverlay { proxy in
            if chartMode == .total {
                GeometryReader { geometry in
                    Rectangle()
                        .fill(.clear)
                        .contentShape(Rectangle())
                        .gesture(
                            DragGesture(minimumDistance: 0)
                                .onChanged { value in
                                    guard let plotFrameAnchor = proxy.plotFrame else { return }
                                    let plotFrame = geometry[plotFrameAnchor]
                                    let x = value.location.x - plotFrame.origin.x
                                    guard let date: Date = proxy.value(atX: x) else { return }

                                    if let closest = data.min(by: {
                                        abs($0.date.timeIntervalSince(date)) < abs($1.date.timeIntervalSince(date))
                                    }) {
                                        selectedDataPoint = closest
                                    }
                                }
                                .onEnded { _ in
                                    selectedDataPoint = nil
                                }
                        )
                }
            }
        }
        .frame(height: 300)
        .zoomableTimeSeries(dates: data.map(\.date), zoom: $zoom)
        // Performance: Use GPU rendering for smoother scrolling on older devices
        .drawingGroup()
    }

    @ChartContentBuilder
    private var chartMarks: some ChartContent {
        switch chartMode {
        case .total:
            ForEach(data, id: \.date) { item in
                LineMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(Color.appPrimary)
                .interpolationMethod(.catmullRom)

                PointMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(Color.appPrimary)
                .symbolSize(data.count <= ChartLabels.alwaysShowThreshold ? 40 : 30)
                .annotation(position: .top, spacing: 3) {
                    if data.count <= ChartLabels.alwaysShowThreshold {
                        ChartValueBubble(text: item.value.compactCurrencyString)
                    }
                }

                AreaMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(
                    LinearGradient(
                        colors: [Color.appPrimary.opacity(0.3), Color.appPrimary.opacity(0.0)],
                        startPoint: .top,
                        endPoint: .bottom
                    )
                )
                .interpolationMethod(.catmullRom)
            }
        case .byCategory:
            ForEach(categoryData) { item in
                AreaMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(by: .value("Category", item.categoryName))
                .interpolationMethod(.catmullRom)
                .opacity(0.5)
            }

            ForEach(stackedCategoryData) { item in
                LineMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(by: .value("Category", item.categoryName))
                .interpolationMethod(.catmullRom)

                PointMark(
                    x: .value("Date", item.date),
                    y: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue)
                )
                .foregroundStyle(by: .value("Category", item.categoryName))
                .symbolSize(18)
            }
        }

        if showGoalLines {
            ForEach(goals) { goal in
                RuleMark(y: .value("Goal", NSDecimalNumber(decimal: goal.targetDecimal).doubleValue))
                    .foregroundStyle(Color.appSecondary.opacity(0.4))
                    .lineStyle(StrokeStyle(lineWidth: 1, dash: [6, 4]))
            }
        }

        // Scrub/tap selection bubble (total mode)
        if chartMode == .total, let sel = selectedDataPoint {
            RuleMark(x: .value("Selected", sel.date))
                .foregroundStyle(Color.secondary.opacity(0.35))
                .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3]))
            PointMark(
                x: .value("Selected", sel.date),
                y: .value("Value", NSDecimalNumber(decimal: sel.value).doubleValue)
            )
            .foregroundStyle(Color.appPrimary)
            .symbolSize(80)
            .annotation(position: .top, spacing: 4) {
                ChartValueBubble(text: sel.value.compactCurrencyString, prominent: true)
            }
        }
    }

    private var chartCategoryNames: [String] {
        let names = Array(Set(categoryData.map { $0.categoryName })).sorted()
        return names
    }

    private var chartCategoryColors: [Color] {
        chartCategoryNames.map { name in
            if let hex = categoryData.first(where: { $0.categoryName == name })?.colorHex {
                return Color(hex: hex) ?? .gray
            }
            return .gray
        }
    }
}

// MARK: - Contributions Chart

struct ContributionsChartView: View {
    let data: [(date: Date, amount: Decimal)]
    @State private var zoom = ChartZoomModel()

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Contributions")
                .font(.headline)

            if data.isEmpty {
                Text("No contributions yet.")
                    .foregroundColor(.secondary)
                    .frame(height: 260)
            } else {
                Chart {
                    ForEach(data, id: \.date) { item in
                        BarMark(
                            x: .value("Month", item.date),
                            y: .value("Amount", NSDecimalNumber(decimal: item.amount).doubleValue)
                        )
                        .foregroundStyle(Color.appSecondary)
                        .cornerRadius(6)
                    }
                }
                .chartXAxis {
                    AxisMarks(values: .stride(by: .month, count: 2)) { value in
                        AxisValueLabel(format: .dateTime.month(.abbreviated))
                    }
                }
                .chartYAxis {
                    AxisMarks(position: .leading) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(Decimal(doubleValue).shortCurrencyString)
                                    .font(.caption)
                            }
                        }
                    }
                }
                .frame(height: 260)
                .zoomableTimeSeries(dates: data.map(\.date), zoom: $zoom)
                ChartStatsRow(stats: contributionStats).padding(.top, 4)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var contributionStats: [ChartStat] {
        guard !data.isEmpty else { return [] }
        let amounts = data.map { NSDecimalNumber(decimal: $0.amount).doubleValue }
        let total = amounts.reduce(0, +)
        let avg = total / Double(amounts.count)
        let highest = amounts.max() ?? 0
        let last = amounts.last ?? 0
        return [
            ChartStat(label: "Total", value: Decimal(total).compactCurrencyString, color: .primary),
            ChartStat(label: "Monthly avg", value: Decimal(avg).compactCurrencyString, color: .secondary),
            ChartStat(label: "Highest", value: Decimal(highest).compactCurrencyString, color: .positiveGreen),
            ChartStat(label: "Last", value: Decimal(last).compactCurrencyString, color: .appPrimary),
        ]
    }
}

// MARK: - Rolling 12-Month Return

struct RollingReturnChartView: View {
    let data: [(date: Date, value: Double)]
    @State private var zoom = ChartZoomModel()
    @State private var selectedDate: Date?

    private var showAllLabels: Bool { data.count <= ChartLabels.alwaysShowThreshold }
    private var selectedPoint: (date: Date, value: Double)? {
        guard let selectedDate else { return nil }
        return data.min(by: {
            abs($0.date.timeIntervalSince(selectedDate)) < abs($1.date.timeIntervalSince(selectedDate))
        })
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Rolling 12-Month Return")
                .font(.headline)

            if data.isEmpty {
                Text("Not enough data for rolling returns.")
                    .foregroundColor(.secondary)
                    .frame(height: 260)
            } else {
                Chart {
                    ForEach(data, id: \.date) { item in
                        LineMark(
                            x: .value("Month", item.date),
                            y: .value("Return", item.value)
                        )
                        .foregroundStyle(Color.appPrimary)
                        .interpolationMethod(.catmullRom)

                        PointMark(
                            x: .value("Month", item.date),
                            y: .value("Return", item.value)
                        )
                        .foregroundStyle(Color.appPrimary)
                        .symbolSize(showAllLabels ? 36 : 24)
                        .annotation(position: item.value >= 0 ? .top : .bottom, spacing: 3) {
                            if showAllLabels {
                                ChartValueBubble(text: ChartLabels.percent(item.value))
                            }
                        }
                    }

                    if let sel = selectedPoint {
                        RuleMark(x: .value("Selected", sel.date))
                            .foregroundStyle(Color.secondary.opacity(0.35))
                            .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3]))
                        PointMark(
                            x: .value("Selected", sel.date),
                            y: .value("Return", sel.value)
                        )
                        .foregroundStyle(Color.appPrimary)
                        .symbolSize(70)
                        .annotation(position: sel.value >= 0 ? .top : .bottom, spacing: 4) {
                            ChartValueBubble(text: ChartLabels.percent(sel.value), prominent: true)
                        }
                    }
                }
                .chartXSelection(value: $selectedDate)
                .chartXAxis {
                    AxisMarks(values: .stride(by: .month, count: 2)) { value in
                        AxisValueLabel(format: .dateTime.month(.abbreviated))
                    }
                }
                .chartYAxis {
                    AxisMarks(position: .leading) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(String(format: "%.1f%%", doubleValue))
                                    .font(.caption)
                            }
                        }
                    }
                }
                .frame(height: 260)
                .zoomableTimeSeries(dates: data.map(\.date), zoom: $zoom)
                ChartStatsRow(stats: rollingStats).padding(.top, 4)
                ChartDataTable(
                    rows: rollingTableRows,
                    valueHeader: "Return",
                    deltaPrevHeader: "Δ prev",
                    deltaFirstHeader: "Δ first"
                )
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var rollingStats: [ChartStat] {
        guard !data.isEmpty else { return [] }
        let values = data.map { $0.value }
        let latest = values.last ?? 0
        let best = values.max() ?? 0
        let worst = values.min() ?? 0
        let avg = values.reduce(0, +) / Double(values.count)
        let change = (values.last ?? 0) - (values.first ?? 0)
        return [
            ChartStat(label: "Latest", value: String(format: "%.1f%%", latest), color: latest >= 0 ? .positiveGreen : .negativeRed),
            ChartStat(label: "Best", value: String(format: "%.1f%%", best), color: .positiveGreen),
            ChartStat(label: "Worst", value: String(format: "%.1f%%", worst), color: .negativeRed),
            ChartStat(label: "Average", value: String(format: "%.1f%%", avg), color: .secondary),
            ChartStat(label: "Change", value: String(format: "%+.1f%%", change), color: change >= 0 ? .positiveGreen : .negativeRed),
        ]
    }

    private var rollingTableRows: [ChartDataTableRow] {
        guard !data.isEmpty else { return [] }
        let firstVal = data.first?.value ?? 0
        return data.enumerated().map { idx, point in
            let prevVal = idx > 0 ? data[idx - 1].value : point.value
            let deltaPrev = point.value - prevVal
            let deltaFirst = point.value - firstVal
            return ChartDataTableRow(
                label: chartTableDateLabel(point.date),
                value: String(format: "%.1f%%", point.value),
                deltaPrev: idx > 0 ? String(format: "%+.1f%%", deltaPrev) : nil,
                deltaFirst: idx > 0 ? String(format: "%+.1f%%", deltaFirst) : nil,
                isPrevPositive: deltaPrev >= 0,
                isFirstPositive: deltaFirst >= 0
            )
        }
    }
}

// MARK: - Risk vs Return

struct RiskReturnChartView: View {
    let data: [(category: String, cagr: Double, volatility: Double, color: String)]

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Risk vs Return")
                .font(.headline)

            if data.isEmpty {
                Text("Not enough data to compare categories.")
                    .foregroundColor(.secondary)
                    .frame(height: 260)
            } else {
                Chart {
                    ForEach(data, id: \.category) { item in
                        PointMark(
                            x: .value("Volatility", item.volatility),
                            y: .value("CAGR", item.cagr)
                        )
                        .foregroundStyle(Color(hex: item.color) ?? .gray)
                        .symbolSize(60)
                        .annotation(position: .top) {
                            Text(item.category)
                                .font(.caption2)
                                .foregroundColor(.secondary)
                        }
                    }
                }
                .chartXAxis {
                    AxisMarks(position: .bottom) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(String(format: "%.1f%%", doubleValue))
                                    .font(.caption)
                            }
                        }
                    }
                }
                .chartYAxis {
                    AxisMarks(position: .leading) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(String(format: "%.1f%%", doubleValue))
                                    .font(.caption)
                            }
                        }
                    }
                }
                .frame(height: 260)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }
}

// MARK: - Net Performance vs Contributions

struct CashflowStackedChartView: View {
    let data: [(date: Date, contributions: Decimal, netPerformance: Decimal)]
    @State private var zoom = ChartZoomModel()

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Net Performance vs Contributions")
                .font(.headline)

            if data.isEmpty {
                Text("Not enough data to compare cashflow.")
                    .foregroundColor(.secondary)
                    .frame(height: 260)
            } else {
                Chart {
                    ForEach(data, id: \.date) { item in
                        let contributionValue = NSDecimalNumber(decimal: item.contributions).doubleValue
                        let netValue = NSDecimalNumber(decimal: item.netPerformance).doubleValue
                        let stackedEnd = contributionValue + netValue

                        BarMark(
                            x: .value("Month", item.date),
                            yStart: .value("Start", 0),
                            yEnd: .value("Contributions", contributionValue)
                        )
                        .foregroundStyle(Color.appSecondary.opacity(0.8))

                        BarMark(
                            x: .value("Month", item.date),
                            yStart: .value("Start", contributionValue),
                            yEnd: .value("Net", stackedEnd)
                        )
                        .foregroundStyle(netValue >= 0 ? Color.positiveGreen : Color.negativeRed)
                    }
                }
                .chartXAxis {
                    AxisMarks(values: .stride(by: .month, count: 2)) { value in
                        AxisValueLabel(format: .dateTime.month(.abbreviated))
                    }
                }
                .chartYAxis {
                    AxisMarks(position: .leading) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(Decimal(doubleValue).shortCurrencyString)
                                    .font(.caption)
                            }
                        }
                    }
                }
                .frame(height: 260)
                .zoomableTimeSeries(dates: data.map(\.date), zoom: $zoom)
                ChartStatsRow(stats: cashflowStats).padding(.top, 4)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var cashflowStats: [ChartStat] {
        guard !data.isEmpty else { return [] }
        let totalContrib = data.reduce(Decimal.zero) { $0 + $1.contributions }
        let totalPerf = data.reduce(Decimal.zero) { $0 + $1.netPerformance }
        let net = totalContrib + totalPerf
        return [
            ChartStat(label: "Contributions", value: totalContrib.compactCurrencyString, color: .appSecondary),
            ChartStat(label: "Market returns", value: totalPerf.compactCurrencyString, color: totalPerf >= 0 ? .positiveGreen : .negativeRed),
            ChartStat(label: "Net total", value: net.compactCurrencyString, color: net >= 0 ? .positiveGreen : .negativeRed),
        ]
    }
}

// MARK: - Allocation Evolution Chart

struct AllocationEvolutionDataPoint: Identifiable {
    let id: String
    let date: Date
    let category: String
    let percentage: Double
    let color: String
}

struct AllocationEvolutionChart: View {
    let data: [(date: Date, category: String, percentage: Double, color: String)]

    private var identifiableData: [AllocationEvolutionDataPoint] {
        data.enumerated().map { index, item in
            AllocationEvolutionDataPoint(
                id: "\(index)-\(item.category)",
                date: item.date,
                category: item.category,
                percentage: item.percentage,
                color: item.color
            )
        }
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Allocation Over Time")
                .font(.headline)

            if data.isEmpty {
                emptyView
            } else {
                chartView
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var emptyView: some View {
        Text("Not enough data to show allocation evolution.")
            .foregroundColor(.secondary)
            .frame(height: 260)
    }

    /// Categories in stable order (preserving the ViewModel's sort: largest overall first)
    private var stableCategoryNames: [String] {
        var seen = Set<String>()
        var ordered: [String] = []
        for item in data {
            if seen.insert(item.category).inserted {
                ordered.append(item.category)
            }
        }
        return ordered
    }

    private var stableCategoryColors: [Color] {
        stableCategoryNames.map { name in
            if let hex = data.first(where: { $0.category == name })?.color {
                return Color(hex: hex) ?? .gray
            }
            return .gray
        }
    }

    private var chartView: some View {
        Chart(identifiableData) { item in
            BarMark(
                x: .value("Date", item.date, unit: .month),
                y: .value("Percentage", item.percentage)
            )
            .foregroundStyle(by: .value("Category", item.category))
        }
        .chartForegroundStyleScale(domain: stableCategoryNames, range: stableCategoryColors)
        .chartXAxis {
            AxisMarks(values: .stride(by: .month, count: 2)) { _ in
                AxisValueLabel(format: .dateTime.month(.abbreviated).year(.twoDigits))
            }
        }
        .chartYAxis {
            AxisMarks(position: .leading) { value in
                AxisValueLabel {
                    if let pct = value.as(Double.self) {
                        Text(String(format: "%.0f%%", pct))
                            .font(.caption)
                    }
                }
            }
        }
        .frame(height: 260)
        .drawingGroup()
    }
}

#Preview {
    ChartsContainerView(iapService: IAPService())
        .environmentObject(AccountStore(iapService: IAPService()))
}
