import SwiftUI
import SwiftData

struct DataTypeTemporalDistributionView: View {
    let current: TypeCount?
    let previous: TypeCount?
    let displayName: String

    @Environment(\.modelContext) private var modelContext
    @State private var viewModel = DataTypeTemporalDistributionViewModel()
    @State private var isRecomputing = false
    @State private var isZoomed: Bool = false
    @State private var displayedSnapshot: HealthSnapshot?
    @Query(sort: \HealthSnapshot.timestamp) private var allSnapshots: [HealthSnapshot]
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @Environment(\.verticalSizeClass) private var verticalSizeClass

    private var isLandscape: Bool {
        horizontalSizeClass == .regular && verticalSizeClass == .compact
    }

    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 currentSnapshot: HealthSnapshot? {
        displayedSnapshot ?? (current?.snapshot ?? allSnapshots.first)
    }

    private var timelineSnapshots: [HealthSnapshot] {
        allSnapshots
            .filter { current?.snapshot?.deviceID ?? "" == $0.deviceID }
            .sorted(by: HealthSnapshot.timelineSort)
    }

    private var previousSnapshot: HealthSnapshot? {
        currentSnapshot?.previousInTimeline(timelineSnapshots)
    }

    private var nextSnapshot: HealthSnapshot? {
        currentSnapshot?.nextInTimeline(timelineSnapshots)
    }

    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)
        .toolbar {
            ToolbarItemGroup(placement: .topBarTrailing) {
                if canResetZoom {
                    Button(action: resetZoom) {
                        Image(systemName: "arrow.up.left.and.arrow.down.right")
                    }
                    .accessibilityLabel("Reset zoom")
                }

                Menu {
                    Picker("Rezoluție", 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(current: current, previous: previous, context: modelContext)
        }
    }

    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

                TemporalDistributionChartView(
                    bins: viewModel.allBins,
                    displayName: displayName,
                    binningStrategy: viewModel.binningStrategy,
                    onBinTap: handleBinTap,
                    onResetZoom: resetZoom
                )

                statisticsSection
            }
            .padding(16)
        }
        .background(Color(.systemBackground))
        .safeAreaInset(edge: .top, spacing: 0) {
            if !timelineSnapshots.isEmpty {
                SnapshotNavigationHeader(
                    snapshots: timelineSnapshots,
                    currentSnapshot: currentSnapshot,
                    onSnapshotSelected: { displayedSnapshot = $0 }
                )
            }
        }
    }

    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(current?.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 = (current?.count ?? 0) + (previous?.count ?? 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("Added", totalAdded, Color.healthyGreen)
                statCard("Disappeared", 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(
            current: .preview,
            previous: .preview,
            displayName: "Sleep"
        )
    }
    .modelContainer(for: [HealthSnapshot.self, TypeCount.self, HealthRecord.self, TypeDistributionBin.self], inMemory: true)
}

extension TypeCount {
    static var preview: TypeCount {
        let count = TypeCount(
            typeIdentifier: "HKCategoryTypeIdentifierSleepAnalysis",
            displayName: "Sleep",
            count: 1000
        )

        let mockRecords = (0..<1000).map { idx in
            let date = Calendar.current.date(byAdding: .day, value: -idx, to: Date.now) ?? .now
            return HealthRecordValue(
                typeIdentifier: count.typeIdentifier,
                sampleUUIDHash: UUID().uuidString,
                recordFingerprint: "fp-\(idx)",
                startDate: date,
                endDate: date.addingTimeInterval(28800),
                displayValue: nil
            )
        }

        count.setRecordValues(mockRecords)
        return count
    }
}
