import SwiftUI
import Charts

struct PredictionChartView: View {
    let predictions: [Prediction]
    let historicalData: [(date: Date, value: Decimal)]
    @State private var selectedDate: Date?

    private var showAllLabels: Bool {
        historicalData.count + predictions.count <= ChartLabels.alwaysShowThreshold
    }

    /// Nearest point (historical or predicted) to the selected date.
    private var selectedPoint: (date: Date, value: Decimal, isPrediction: Bool)? {
        guard let selectedDate else { return nil }
        let all: [(date: Date, value: Decimal, isPrediction: Bool)] =
            historicalData.map { ($0.date, $0.value, false) } +
            predictions.map { ($0.date, $0.predictedValue, true) }
        return all.min(by: {
            abs($0.date.timeIntervalSince(selectedDate)) < abs($1.date.timeIntervalSince(selectedDate))
        })
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            HStack {
                Text(predictions.isEmpty ? "Prediction" : "\(predictions.count)-Month Prediction")
                    .font(.headline)

                Spacer()

                if let lastPrediction = predictions.last {
                    VStack(alignment: .trailing, spacing: 2) {
                        Text("Forecast")
                            .font(.caption)
                            .foregroundColor(.secondary)
                        Text(lastPrediction.formattedValue)
                            .font(.subheadline.weight(.semibold))
                            .foregroundColor(.appPrimary)
                    }
                }
            }

            if let algorithm = predictions.first?.algorithm {
                Text("Algorithm: \(algorithm.displayName)")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            if !predictions.isEmpty && historicalData.count >= 2 {
                Chart {
                    // Historical data
                    ForEach(historicalData, 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(showAllLabels ? 36 : 24)
                        .annotation(position: .top, spacing: 3) {
                            if showAllLabels {
                                ChartValueBubble(text: item.value.compactCurrencyString)
                            }
                        }
                    }

                    // Confidence interval area
                    ForEach(predictions) { prediction in
                        AreaMark(
                            x: .value("Date", prediction.date),
                            yStart: .value("Lower", NSDecimalNumber(decimal: prediction.confidenceInterval.lower).doubleValue),
                            yEnd: .value("Upper", NSDecimalNumber(decimal: prediction.confidenceInterval.upper).doubleValue)
                        )
                        .foregroundStyle(Color.appSecondary.opacity(0.2))
                    }

                    // Prediction line
                    ForEach(predictions) { prediction in
                        LineMark(
                            x: .value("Date", prediction.date),
                            y: .value("Predicted", NSDecimalNumber(decimal: prediction.predictedValue).doubleValue)
                        )
                        .foregroundStyle(Color.appSecondary)
                        .lineStyle(StrokeStyle(lineWidth: 2, dash: [5, 5]))

                        PointMark(
                            x: .value("Date", prediction.date),
                            y: .value("Predicted", NSDecimalNumber(decimal: prediction.predictedValue).doubleValue)
                        )
                        .foregroundStyle(Color.appSecondary)
                        .symbolSize(showAllLabels ? 36 : 24)
                        .annotation(position: .top, spacing: 3) {
                            if showAllLabels {
                                ChartValueBubble(text: prediction.predictedValue.compactCurrencyString, color: .appSecondary)
                            }
                        }
                    }

                    // Bull scenario line (upper confidence interval)
                    ForEach(predictions) { prediction in
                        LineMark(
                            x: .value("Date", prediction.date),
                            y: .value("Bull", NSDecimalNumber(decimal: prediction.confidenceInterval.upper).doubleValue),
                            series: .value("Scenario", "bull")
                        )
                        .foregroundStyle(Color.positiveGreen.opacity(0.7))
                        .lineStyle(StrokeStyle(lineWidth: 1.5, dash: [4, 3]))
                    }

                    // Bear scenario line (lower confidence interval)
                    ForEach(predictions) { prediction in
                        LineMark(
                            x: .value("Date", prediction.date),
                            y: .value("Bear", NSDecimalNumber(decimal: prediction.confidenceInterval.lower).doubleValue),
                            series: .value("Scenario", "bear")
                        )
                        .foregroundStyle(Color.negativeRed.opacity(0.7))
                        .lineStyle(StrokeStyle(lineWidth: 1.5, dash: [4, 3]))
                    }

                    // Connect historical to prediction
                    if let lastHistorical = historicalData.last,
                       let firstPrediction = predictions.first {
                        LineMark(
                            x: .value("Date", lastHistorical.date),
                            y: .value("Value", NSDecimalNumber(decimal: lastHistorical.value).doubleValue),
                            series: .value("Connection", "connect")
                        )
                        .foregroundStyle(Color.appSecondary)
                        .lineStyle(StrokeStyle(lineWidth: 2, dash: [5, 5]))

                        LineMark(
                            x: .value("Date", firstPrediction.date),
                            y: .value("Value", NSDecimalNumber(decimal: firstPrediction.predictedValue).doubleValue),
                            series: .value("Connection", "connect")
                        )
                        .foregroundStyle(Color.appSecondary)
                        .lineStyle(StrokeStyle(lineWidth: 2, dash: [5, 5]))
                    }

                    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("Value", NSDecimalNumber(decimal: sel.value).doubleValue)
                        )
                        .foregroundStyle(sel.isPrediction ? Color.appSecondary : Color.appPrimary)
                        .symbolSize(80)
                        .annotation(position: .top, spacing: 4) {
                            ChartValueBubble(
                                text: sel.value.compactCurrencyString,
                                color: sel.isPrediction ? .appSecondary : .appPrimary,
                                prominent: true
                            )
                        }
                    }
                }
                .chartXSelection(value: $selectedDate)
                .chartXAxis {
                    AxisMarks(values: .stride(by: .month, count: 3)) { value in
                        AxisValueLabel(format: .dateTime.month(.abbreviated).year(.twoDigits))
                    }
                }
                .chartYAxis {
                    AxisMarks(position: .leading) { value in
                        AxisValueLabel {
                            if let doubleValue = value.as(Double.self) {
                                Text(Decimal(doubleValue).shortCurrencyString)
                                    .font(.caption)
                            }
                        }
                    }
                }
                .frame(height: 280)

                // Stats row
                if let currentValue = historicalData.last?.value,
                   let lastPred = predictions.last {
                    ChartStatsRow(stats: [
                        ChartStat(label: "Current", value: currentValue.compactCurrencyString, color: .appPrimary),
                        ChartStat(label: "Base (\(predictions.count)M)", value: lastPred.predictedValue.compactCurrencyString, color: .appSecondary),
                        ChartStat(label: "Bull case", value: lastPred.confidenceInterval.upper.compactCurrencyString, color: .positiveGreen),
                        ChartStat(label: "Bear case", value: lastPred.confidenceInterval.lower.compactCurrencyString, color: .negativeRed),
                    ])
                }

                // Legend
                HStack(spacing: 20) {
                    HStack(spacing: 6) {
                        Rectangle()
                            .fill(Color.appPrimary)
                            .frame(width: 20, height: 3)
                        Text("Historical")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }

                    HStack(spacing: 6) {
                        Rectangle()
                            .fill(Color.appSecondary)
                            .frame(width: 20, height: 3)
                            .mask(
                                HStack(spacing: 2) {
                                    ForEach(0..<5, id: \.self) { _ in
                                        Rectangle()
                                            .frame(width: 3)
                                    }
                                }
                            )
                        Text("Prediction")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }

                    HStack(spacing: 6) {
                        Rectangle()
                            .fill(Color.appSecondary.opacity(0.3))
                            .frame(width: 20, height: 10)
                        Text("Confidence")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }

                    HStack(spacing: 6) {
                        Rectangle()
                            .fill(Color.positiveGreen.opacity(0.7))
                            .frame(width: 20, height: 2)
                        Text("Bull")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }

                    HStack(spacing: 6) {
                        Rectangle()
                            .fill(Color.negativeRed.opacity(0.7))
                            .frame(width: 20, height: 2)
                        Text("Bear")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                }

                // Prediction details
                if let lastPrediction = predictions.last {
                    Divider()
                        .padding(.vertical, 8)

                    VStack(spacing: 12) {
                        HStack {
                            Text("12-Month Forecast")
                                .font(.subheadline)
                            Spacer()
                            Text(lastPrediction.formattedValue)
                                .font(.subheadline.weight(.semibold))
                        }

                        HStack {
                            Text("Confidence Range")
                                .font(.subheadline)
                            Spacer()
                            Text(lastPrediction.formattedConfidenceRange)
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }

                        if let currentValue = historicalData.last?.value {
                            let change = lastPrediction.predictedValue - currentValue
                            let changePercent = currentValue > 0
                                ? NSDecimalNumber(decimal: change / currentValue).doubleValue * 100
                                : 0

                            HStack {
                                Text("Expected Change")
                                    .font(.subheadline)
                                Spacer()
                                HStack(spacing: 4) {
                                    Image(systemName: change >= 0 ? "arrow.up.right" : "arrow.down.right")
                                        .font(.caption)
                                    Text(String(format: "%+.1f%%", changePercent))
                                        .font(.subheadline.weight(.medium))
                                }
                                .foregroundColor(change >= 0 ? .positiveGreen : .negativeRed)
                            }
                        }
                    }

                    Divider().padding(.vertical, 4)
                    ChartDataTable(
                        rows: predictionTableRows,
                        valueHeader: "Base",
                        deltaPrevHeader: "Bull",
                        deltaFirstHeader: "Bear"
                    )
                }
            } else {
                VStack(spacing: 12) {
                    Image(systemName: "wand.and.stars")
                        .font(.system(size: 40))
                        .foregroundColor(.secondary)

                    Text("Not enough data for predictions")
                        .font(.subheadline)
                        .foregroundColor(.secondary)

                    Text("Add at least 3 snapshots to generate predictions")
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .multilineTextAlignment(.center)
                }
                .frame(height: 280)
                .frame(maxWidth: .infinity)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var predictionTableRows: [ChartDataTableRow] {
        predictions.map { pred in
            ChartDataTableRow(
                label: chartTableDateLabel(pred.date),
                value: pred.predictedValue.compactCurrencyString,
                deltaPrev: pred.confidenceInterval.upper.compactCurrencyString,
                deltaFirst: pred.confidenceInterval.lower.compactCurrencyString,
                isPrevPositive: true,
                isFirstPositive: false
            )
        }
    }
}

#Preview {
    let historicalData: [(date: Date, value: Decimal)] = [
        (Date().adding(months: -6), 10000),
        (Date().adding(months: -5), 10500),
        (Date().adding(months: -4), 10200),
        (Date().adding(months: -3), 11000),
        (Date().adding(months: -2), 11500),
        (Date().adding(months: -1), 11200),
        (Date(), 12000)
    ]

    let predictions = [
        Prediction(
            date: Date().adding(months: 3),
            predictedValue: 13000,
            algorithm: .linear,
            confidenceInterval: Prediction.ConfidenceInterval(lower: 12000, upper: 14000)
        ),
        Prediction(
            date: Date().adding(months: 6),
            predictedValue: 14000,
            algorithm: .linear,
            confidenceInterval: Prediction.ConfidenceInterval(lower: 12500, upper: 15500)
        ),
        Prediction(
            date: Date().adding(months: 9),
            predictedValue: 15000,
            algorithm: .linear,
            confidenceInterval: Prediction.ConfidenceInterval(lower: 13000, upper: 17000)
        ),
        Prediction(
            date: Date().adding(months: 12),
            predictedValue: 16000,
            algorithm: .linear,
            confidenceInterval: Prediction.ConfidenceInterval(lower: 13500, upper: 18500)
        )
    ]

    return PredictionChartView(predictions: predictions, historicalData: historicalData)
        .padding()
}
