import SwiftUI
import Charts

struct PeriodComparisonChartView: View {
    @State private var selectedMonth: Int?

    /// Period charts are short by design (a handful of months) — labels always help.
    private var showAllLabels: Bool {
        (viewModel.periodComparisonData.map { $0.points.count }.max() ?? 0) <= ChartLabels.alwaysShowThreshold
    }

    private func selectionRows(for month: Int) -> [(label: String, value: String, color: Color)] {
        viewModel.periodComparisonData.compactMap { series in
            guard let point = series.points.first(where: { $0.monthOffset == month }) else { return nil }
            return (series.label, ChartLabels.percent(point.returnPct), Color(hex: series.colorHex) ?? .gray)
        }
    }

    @ObservedObject var viewModel: ChartsViewModel

    private let colorA = Color(hex: "#3478F6") ?? .blue
    private let colorB = Color(hex: "#FF9500") ?? .orange

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Period vs Period")
                .font(.headline)

            periodPickersSection
            chartContent
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    // MARK: - Period Pickers

    private var periodPickersSection: some View {
        VStack(spacing: 8) {
            periodRow(label: "Period A", color: colorA, start: $viewModel.periodAStart, end: $viewModel.periodAEnd)
            Divider()
                .background(Color.secondary.opacity(0.15))
            periodRow(label: "Period B", color: colorB, start: $viewModel.periodBStart, end: $viewModel.periodBEnd)
        }
        .padding(12)
        .background(
            LinearGradient(
                colors: [colorA.opacity(0.06), colorB.opacity(0.06)],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
        )
        .cornerRadius(12)
        .overlay(
            RoundedRectangle(cornerRadius: 12)
                .stroke(Color.secondary.opacity(0.1), lineWidth: 1)
        )
    }

    private func periodRow(label: String, color: Color, start: Binding<Date>, end: Binding<Date>) -> some View {
        HStack(spacing: 10) {
            RoundedRectangle(cornerRadius: 2)
                .fill(color)
                .frame(width: 3, height: 30)

            Text(label)
                .font(.caption.weight(.bold))
                .foregroundColor(color)
                .frame(width: 60, alignment: .leading)

            DatePicker(
                "",
                selection: Binding<Date>(
                    get: { firstOfMonth(start.wrappedValue) },
                    set: { start.wrappedValue = firstOfMonth($0) }
                ),
                displayedComponents: [.date]
            )
            .datePickerStyle(.compact)
            .labelsHidden()
            .frame(maxWidth: .infinity)

            Text("→")
                .font(.caption)
                .foregroundColor(.secondary)

            DatePicker(
                "",
                selection: Binding<Date>(
                    get: { firstOfMonth(end.wrappedValue) },
                    set: { end.wrappedValue = firstOfMonth($0) }
                ),
                displayedComponents: [.date]
            )
            .datePickerStyle(.compact)
            .labelsHidden()
            .frame(maxWidth: .infinity)
        }
    }

    // MARK: - Chart Content

    @ViewBuilder
    private var chartContent: some View {
        if viewModel.periodComparisonData.isEmpty {
            emptyView
        } else {
            VStack(spacing: 16) {
                numericalSummary
                periodChart
                legend
            }
        }
    }

    private var numericalSummary: some View {
        HStack(spacing: 12) {
            ForEach(viewModel.periodComparisonData) { series in
                let color = Color(hex: series.colorHex) ?? .gray
                let finalReturn = series.points.last?.returnPct ?? 0
                let maxReturn = series.points.map { $0.returnPct }.max() ?? 0
                let minReturn = series.points.map { $0.returnPct }.min() ?? 0

                HStack(spacing: 0) {
                    Rectangle()
                        .fill(color)
                        .frame(width: 4)

                    VStack(alignment: .leading, spacing: 6) {
                        HStack(spacing: 4) {
                            Circle()
                                .fill(color)
                                .frame(width: 6, height: 6)
                            Text(series.label)
                                .font(.caption2.weight(.medium))
                                .foregroundColor(.secondary)
                                .lineLimit(1)
                        }
                        Text(String(format: "%+.2f%%", finalReturn))
                            .font(.title2.weight(.bold))
                            .foregroundColor(finalReturn >= 0 ? .positiveGreen : .negativeRed)
                        HStack(spacing: 10) {
                            HStack(spacing: 3) {
                                Image(systemName: "arrow.up")
                                    .font(.caption2.weight(.semibold))
                                    .foregroundColor(.positiveGreen)
                                Text(String(format: "%.1f%%", maxReturn))
                                    .font(.caption2)
                                    .foregroundColor(.positiveGreen)
                            }
                            HStack(spacing: 3) {
                                Image(systemName: "arrow.down")
                                    .font(.caption2.weight(.semibold))
                                    .foregroundColor(.negativeRed)
                                Text(String(format: "%.1f%%", minReturn))
                                    .font(.caption2)
                                    .foregroundColor(.negativeRed)
                            }
                        }
                    }
                    .padding(.horizontal, 12)
                    .padding(.vertical, 10)
                    .frame(maxWidth: .infinity, alignment: .leading)
                }
                .background(color.opacity(0.07))
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(color.opacity(0.15), lineWidth: 1)
                )
            }
        }
    }

    private var emptyView: some View {
        VStack(spacing: 12) {
            Image(systemName: "calendar.badge.clock")
                .font(.system(size: 36))
                .foregroundColor(.secondary)
            Text("No data available for the selected periods.")
                .font(.subheadline)
                .foregroundColor(.secondary)
                .multilineTextAlignment(.center)
        }
        .frame(maxWidth: .infinity)
        .frame(height: 260)
    }

    // MARK: - Flat data for Chart

    private struct PeriodPoint: Identifiable {
        let id: String
        let seriesId: String
        let seriesLabel: String
        let colorHex: String
        let monthOffset: Int
        let returnPct: Double
    }

    private var flatPoints: [PeriodPoint] {
        var result: [PeriodPoint] = []
        for series in viewModel.periodComparisonData {
            for point in series.points {
                result.append(PeriodPoint(
                    id: "\(series.id)-\(point.monthOffset)",
                    seriesId: series.id,
                    seriesLabel: series.label,
                    colorHex: series.colorHex,
                    monthOffset: point.monthOffset,
                    returnPct: point.returnPct
                ))
            }
        }
        return result
    }

    private var periodChart: some View {
        let points = flatPoints
        let seriesIds = viewModel.periodComparisonData.map { $0.id }
        let seriesColors: [Color] = viewModel.periodComparisonData.map {
            Color(hex: $0.colorHex) ?? .gray
        }

        return Chart {
            ForEach(points) { point in
                LineMark(
                    x: .value("Month", point.monthOffset),
                    y: .value("Return", point.returnPct),
                    series: .value("Period", point.seriesLabel)
                )
                .interpolationMethod(.catmullRom)
                .foregroundStyle(by: .value("Period", point.seriesLabel))
                .lineStyle(StrokeStyle(lineWidth: 2.5))

                PointMark(
                    x: .value("Month", point.monthOffset),
                    y: .value("Return", point.returnPct)
                )
                .foregroundStyle(by: .value("Period", point.seriesLabel))
                .symbolSize(showAllLabels ? 40 : 30)
                .annotation(position: point.seriesLabel == viewModel.periodComparisonData.first?.label ? .top : .bottom,
                            spacing: 3) {
                    if showAllLabels {
                        ChartValueBubble(
                            text: ChartLabels.percent(point.returnPct),
                            color: Color(hex: point.colorHex) ?? .gray
                        )
                    }
                }
            }

            RuleMark(y: .value("Zero", 0))
                .foregroundStyle(Color.secondary.opacity(0.4))
                .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 4]))

            if let selectedMonth {
                RuleMark(x: .value("Selected", selectedMonth))
                    .foregroundStyle(Color.secondary.opacity(0.35))
                    .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3]))
                    .annotation(position: .top, spacing: 4) {
                        ChartSelectionCard(
                            title: "M\(selectedMonth + 1)",
                            rows: selectionRows(for: selectedMonth)
                        )
                    }
            }
        }
        .chartXSelection(value: $selectedMonth)
        .chartForegroundStyleScale(
            domain: viewModel.periodComparisonData.map { $0.label },
            range: seriesColors
        )
        .chartXAxis {
            AxisMarks(values: xAxisValues) { value in
                AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5, dash: [3, 3]))
                    .foregroundStyle(Color.secondary.opacity(0.2))
                AxisValueLabel {
                    if let idx = value.as(Int.self) {
                        Text("M\(idx + 1)")
                            .font(.caption2)
                    }
                }
            }
        }
        .chartYAxis {
            AxisMarks(position: .leading) { value in
                AxisValueLabel {
                    if let d = value.as(Double.self) {
                        Text(String(format: "%.1f%%", d))
                            .font(.caption2)
                    }
                }
                AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5, dash: [3, 3]))
                    .foregroundStyle(Color.secondary.opacity(0.15))
            }
        }
        .frame(height: 260)
        .drawingGroup()
        .onChange(of: seriesIds) { _, _ in }
    }

    private var legend: some View {
        HStack(spacing: 16) {
            ForEach(viewModel.periodComparisonData) { series in
                HStack(spacing: 6) {
                    RoundedRectangle(cornerRadius: 2)
                        .fill(Color(hex: series.colorHex) ?? .gray)
                        .frame(width: 20, height: 3)
                    Text(series.label)
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            }
            Spacer()
        }
    }

    // MARK: - Helpers

    private var xAxisValues: [Int] {
        let maxOffset = viewModel.periodComparisonData
            .flatMap { $0.points }
            .map { $0.monthOffset }
            .max() ?? 0
        return Array(0...maxOffset)
    }

    private func firstOfMonth(_ date: Date) -> Date {
        let calendar = Calendar.current
        var components = calendar.dateComponents([.year, .month], from: date)
        components.day = 1
        return calendar.date(from: components) ?? date
    }
}
