import SwiftUI

struct DataTypeTemporalDistributionView: View {
    let input: TemporalDistributionInput?
    let displayName: String

    @Environment(AppSettings.self) private var appSettings
    @Environment(\.dynamicTypeSize) private var dynamicTypeSize
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @State private var viewModel = DataTypeTemporalDistributionViewModel()
    @State private var isZoomed: Bool = false
    @State private var contentWidth: CGFloat = 744

    private var canResetZoom: Bool {
        guard let dateRange = viewModel.dateRange,
              let displayedRange = viewModel.displayedDateRange else { return false }
        return abs(dateRange.start.timeIntervalSince(displayedRange.start)) > 86400 ||
               abs(dateRange.end.timeIntervalSince(displayedRange.end)) > 86400
    }

    private var usesSimplifiedDetailUI: Bool {
        LegacyUIMode.isEnabled(
            forceEnabled: appSettings.simplifiedUIModeEnabled,
            horizontalSizeClass: horizontalSizeClass,
            dynamicTypeSize: dynamicTypeSize,
            screenWidth: contentWidth
        )
    }

    var body: some View {
        Group {
            if viewModel.isLoading {
                loadingView
            } else if let error = viewModel.error {
                errorView(error)
            } else if !viewModel.hasData {
                emptyStateView
            } else {
                contentView
            }
        }
        .navigationTitle(displayName)
        .navigationBarTitleDisplayMode(.inline)
        .background(contentWidthReader)
        .toolbar {
            ToolbarItemGroup(placement: .topBarTrailing) {
                if canResetZoom && !usesSimplifiedDetailUI {
                    Button(action: resetZoom) {
                        Image(systemName: "arrow.up.left.and.arrow.down.right")
                    }
                    .accessibilityLabel("Reset zoom")
                }

                if !usesSimplifiedDetailUI {
                    Menu {
                        Picker("Resolution", selection: $viewModel.binningStrategy) {
                            ForEach(BinningStrategy.allCases, id: \.self) { strategy in
                                Text(strategy.rawValue).tag(strategy)
                            }
                        }
                    } label: {
                        Image(systemName: "line.3.horizontal.decrease.circle")
                    }
                    .accessibilityLabel("Select resolution")
                }
            }
        }
        .task {
            await viewModel.load(input: input)
        }
    }

    private var contentWidthReader: some View {
        GeometryReader { proxy in
            Color.clear
                .onAppear {
                    contentWidth = proxy.size.width
                }
                .onChange(of: proxy.size.width) { _, newWidth in
                    contentWidth = newWidth
                }
        }
    }

    private var loadingView: some View {
        VStack(spacing: 12) {
            ProgressView()
            Text("Preparing temporal distribution...")
                .font(.subheadline)
                .foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(.systemBackground))
    }

    private func errorView(_ message: String) -> some View {
        VStack(spacing: 12) {
            Image(systemName: "exclamationmark.triangle.fill")
                .font(.system(size: 32, weight: .semibold))
                .foregroundStyle(Color.warningAmber)

            Text(message)
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
        }
        .padding(24)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(.systemBackground))
    }

    private var emptyStateView: some View {
        VStack(spacing: 12) {
            Image(systemName: "waveform.path.ecg")
                .font(.system(size: 32, weight: .semibold))
                .foregroundStyle(.secondary)

            Text("No data available")
                .font(.headline)
                .foregroundStyle(.primary)

            Text("Cannot generate temporal distribution without record history.")
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
        }
        .padding(24)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(.systemBackground))
    }

    private var contentView: some View {
        ScrollView {
            VStack(spacing: 16) {
                summarySection

                if usesSimplifiedDetailUI {
                    simplifiedDistributionRows
                } else {
                    TemporalDistributionChartView(
                        bins: viewModel.allBins,
                        displayName: displayName,
                        binningStrategy: viewModel.binningStrategy,
                        onBinTap: handleBinTap,
                        onResetZoom: resetZoom
                    )
                }

                statisticsSection
            }
            .padding(16)
        }
        .background(Color(.systemBackground))
    }

    private var simplifiedDistributionRows: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Buckets")
                .font(.headline.weight(.semibold))

            ForEach(Array(viewModel.allBins.prefix(24).enumerated()), id: \.offset) { _, bin in
                VStack(alignment: .leading, spacing: 6) {
                    Text(bin.date.formatted(.dateTime.year().month().day()))
                        .font(.caption.weight(.semibold))
                        .foregroundStyle(.secondary)

                    HStack(spacing: 12) {
                        compactBucketValue("New", bin.added, .healthyGreen)
                        compactBucketValue("Missing", bin.disappeared, .criticalRed)
                        compactBucketValue("Same", bin.unchanged, .secondary)
                    }
                }
                .padding(10)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private func compactBucketValue(_ label: String, _ value: Int, _ color: Color) -> some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)
            Text("\(value)")
                .font(.caption.weight(.semibold).monospacedDigit())
                .foregroundStyle(color)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    private var summarySection: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Time Period")
                        .font(.caption)
                        .foregroundStyle(.secondary)

                    if let dateRange = viewModel.dateRange {
                        Text("\(dateRange.start.formatted(.dateTime.year().month().day())) – \(dateRange.end.formatted(.dateTime.year().month().day()))")
                            .font(.subheadline.weight(.semibold))
                    }
                }

                Spacer()

                VStack(alignment: .trailing, spacing: 4) {
                    Text("Duration")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Text(durationText)
                        .font(.subheadline.weight(.semibold))
                        .monospacedDigit()
                }
            }
            .padding(12)
            .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))

            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Samples")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Text(sampleCountText)
                        .font(.subheadline.weight(.semibold))
                        .monospacedDigit()
                }

                Spacer()

                VStack(alignment: .trailing, spacing: 4) {
                    Text("Comparing")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Text(input?.displayName ?? displayName)
                        .font(.caption)
                        .foregroundStyle(.primary)
                        .lineLimit(1)
                }
            }
            .padding(12)
            .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
        }
    }

    private var durationText: String {
        guard let dateRange = viewModel.dateRange else { return "–" }
        let days = Int(dateRange.end.timeIntervalSince(dateRange.start) / 86400)
        return "\(days)d"
    }

    private var sampleCountText: String {
        let count = (input?.currentCount ?? 0) + (input?.previousCount ?? 0)
        return formatHumanReadable(count)
    }

    private func formatHumanReadable(_ value: Int) -> String {
        if value >= 1_000_000 {
            let millions = Double(value) / 1_000_000
            return String(format: "%.1f", millions) + "m"
        } else if value >= 1_000 {
            let thousands = Double(value) / 1_000
            return String(format: "%.1f", thousands) + "k"
        } else {
            return "\(value)"
        }
    }

    private var statisticsSection: some View {
        let totalAdded = viewModel.allBins.map(\.added).reduce(0, +)
        let totalDisappeared = viewModel.allBins.map(\.disappeared).reduce(0, +)
        let totalUnchanged = viewModel.allBins.map(\.unchanged).reduce(0, +)

        return VStack(alignment: .leading, spacing: 12) {
            Text("Summary Statistics")
                .font(.headline.weight(.semibold))
                .foregroundStyle(.primary)

            HStack(spacing: 12) {
                statCard("New", totalAdded, Color.healthyGreen)
                statCard("Missing", totalDisappeared, Color.criticalRed)
                statCard("Unchanged", totalUnchanged, Color.neutralGray)
            }

            VStack(alignment: .leading, spacing: 8) {
                HStack {
                    Text("Change Rate")
                        .font(.subheadline.weight(.semibold))
                    Spacer()
                    Text(changeRateText(added: totalAdded, disappeared: totalDisappeared))
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                }
                .padding(12)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
            }
        }
    }

    private func statCard(_ label: String, _ value: Int, _ color: Color) -> some View {
        VStack(alignment: .center, spacing: 8) {
            Text(label)
                .font(.caption)
                .foregroundStyle(.secondary)

            Text("\(value)")
                .font(.headline.weight(.semibold))
                .foregroundStyle(color)
                .monospacedDigit()
        }
        .frame(maxWidth: .infinity)
        .padding(12)
        .background(color.opacity(0.1), in: RoundedRectangle(cornerRadius: 8))
    }

    private func changeRateText(added: Int, disappeared: Int) -> String {
        let total = added + disappeared
        guard total > 0 else { return "No changes" }
        let netChange = added - disappeared
        let rate = Double(netChange) / Double(total) * 100
        let symbol = netChange >= 0 ? "+" : ""
        return "\(symbol)\(String(format: "%.1f", rate))%"
    }

    private func handleBinTap(_ bin: TemporalBin) {
        let strategy = viewModel.binningStrategy
        let zoomedRange = strategy.dateRange(containing: bin.date)

        viewModel.displayedDateRange = zoomedRange
        isZoomed = true

        Task {
            await viewModel.rebuildBinsBackground()
        }
    }

    private func resetZoom() {
        guard let fullRange = viewModel.dateRange else { return }

        viewModel.displayedDateRange = fullRange
        isZoomed = false

        Task {
            await viewModel.rebuildBinsBackground()
        }
    }
}

#Preview {
    NavigationStack {
        DataTypeTemporalDistributionView(
            input: .preview,
            displayName: "Sleep"
        )
    }
    .environment(AppSettings())
}

extension TemporalDistributionInput {
    static var preview: TemporalDistributionInput {
        let now = Date.now
        let bins = (0..<60).map { idx in
            TypeCountDailyChangeBin(
                dayStart: Calendar.current.date(byAdding: .day, value: -idx, to: now) ?? now,
                added: idx.isMultiple(of: 3) ? 8 : 2,
                disappeared: idx.isMultiple(of: 5) ? 3 : 0,
                unchanged: 40 + idx
            )
        }

        return TemporalDistributionInput(
            displayName: "Sleep",
            currentCount: 1_000,
            previousCount: 940,
            detailCache: TypeCountDetailCache(
                baselineSnapshotID: UUID(),
                addedCount: 160,
                disappearedCount: 48,
                addedPreviewRecords: [],
                disappearedPreviewRecords: [],
                dailyChangeBins: bins,
                earliestRecordDate: bins.last?.dayStart,
                latestRecordDate: bins.first?.dayStart
            )
        )
    }
}
