import SwiftUI
import SwiftData

struct DataTypeSnapshotDetailView: View {
    let snapshot: HealthSnapshot
    let typeIdentifier: String
    let displayName: String

    @Environment(\.modelContext) private var modelContext
    @Query(sort: \HealthSnapshot.timestamp) private var allSnapshots: [HealthSnapshot]
    @Query private var allDeltas: [SnapshotDelta]

    @State private var displayedSnapshot: HealthSnapshot?
    @State private var diffState: RecordDiffState = .idle
    @State private var showAddedRecords = false
    @State private var showDisappearedRecords = false
    @State private var showTemporalDistribution = false
    @State private var detailCacheDiagnostic: String?

    private var currentSnapshot: HealthSnapshot {
        displayedSnapshot ?? snapshot
    }

    private var timelineSnapshots: [HealthSnapshot] {
        allSnapshots.filter { candidate in
            if currentSnapshot.deviceID.isEmpty {
                return candidate.deviceID.isEmpty
            }
            return candidate.deviceID == currentSnapshot.deviceID
        }
        .sorted(by: HealthSnapshot.timelineSort)
    }

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

    private var currentTypeCount: TypeCount? {
        typeCount(in: currentSnapshot)
    }

    private var previousTypeCount: TypeCount? {
        previousSnapshot.flatMap(typeCount(in:))
    }

    private var isCurrentTypeContentAliasToPrevious: Bool {
        guard let currentTypeCount,
              let previousTypeCount else { return false }
        return currentTypeCount.contentEquivalentTypeCountID == previousTypeCount.contentRepresentativeTypeCountID
    }

    private var hasTemporalDistributionCache: Bool {
        guard let currentTypeCount,
              let previousSnapshot else { return false }
        return currentTypeCount.detailCache?.matchesBaseline(previousSnapshot.id) == true
    }

    private var currentDelta: SnapshotDelta? {
        guard let previousSnapshot else { return nil }
        return allDeltas.first {
            $0.toSnapshotID == currentSnapshot.id &&
            $0.fromSnapshotID == previousSnapshot.id
        }
    }

    private var currentTypeDelta: TypeDelta? {
        currentDelta?.typeDeltas?.first { $0.typeIdentifier == typeIdentifier }
    }

    private var diffTaskID: String {
        [
            currentSnapshot.id.uuidString,
            previousSnapshot?.id.uuidString ?? "none",
            typeIdentifier
        ].joined(separator: "|")
    }

    private var totalDelta: Int? {
        guard previousSnapshot != nil,
              let currentCount = countValue(for: currentTypeCount),
              let previousCount = countValue(for: previousTypeCount) else { return nil }
        return currentCount - previousCount
    }

    private var currentCountText: String {
        countText(for: currentTypeCount)
    }

    private var previousCountText: String {
        countText(for: previousTypeCount)
    }

    private var quickCurrentCountValue: Int {
        max(currentTypeCount?.count ?? 0, 0)
    }

    private var quickPreviousCountValue: Int {
        max(previousTypeCount?.count ?? 0, 0)
    }

    private var quickAddedDisappeared: (added: Int, disappeared: Int, exact: Bool) {
        if let previousSnapshot,
           let cache = currentTypeCount?.detailCache,
           cache.matchesBaseline(previousSnapshot.id) {
            return (cache.addedCount, cache.disappearedCount, true)
        }

        let net = (currentTypeDelta?.countDelta ?? (quickCurrentCountValue - quickPreviousCountValue))
        return (max(net, 0), max(-net, 0), false)
    }

    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                if previousSnapshot == nil {
                    emptyStateContent("No baseline available for this device.", icon: "clock.badge.questionmark")
                } else if currentTypeCount == nil && previousTypeCount == nil {
                    emptyStateContent("Data type not tracked in selected snapshots.", icon: "eye.slash")
                } else {
                    dataRangeSection
                    recordChangeComparisonSection
                    recordChangeEvolutionSection
                    temporalDistributionSection
                }
            }
            .padding(16)
        }
        .navigationTitle(displayName)
        .navigationBarTitleDisplayMode(.inline)
        .safeAreaInset(edge: .top, spacing: 0) {
            SnapshotNavigationHeader(
                snapshots: timelineSnapshots,
                currentSnapshot: currentSnapshot,
                onSnapshotSelected: { displayedSnapshot = $0 }
            )
                .frame(height: 64)
        }
        .toolbar {
            ToolbarItem(placement: .principal) {
                snapshotToolbarTitle
            }
        }
        .task(id: diffTaskID) {
            await loadRecordDiff()
        }
        .navigationDestination(isPresented: $showTemporalDistribution) {
            DataTypeTemporalDistributionView(
                current: currentTypeCount,
                previous: previousTypeCount,
                displayName: displayName
            )
        }
    }

    private func typeCount(in snapshot: HealthSnapshot) -> TypeCount? {
        snapshot.typeCounts?.first { $0.typeIdentifier == typeIdentifier }
    }

    private func countText(for typeCount: TypeCount?) -> String {
        guard let typeCount else { return "Not tracked" }
        if typeCount.isUnsupported { return "Unsupported" }
        if typeCount.count < 0 { return "Unavailable" }
        return "\(typeCount.count)"
    }

    private func countValue(for typeCount: TypeCount?) -> Int? {
        guard let typeCount else { return 0 }
        guard !typeCount.isUnsupported, typeCount.count >= 0 else { return nil }
        return typeCount.count
    }

    @ViewBuilder
    private var snapshotToolbarTitle: some View {
        if #available(iOS 26.0, *) {
            Text(displayName)
                .font(.headline.weight(.semibold))
                .lineLimit(1)
                .padding(.horizontal, 18)
                .frame(height: 36)
                .background(Color(.systemBackground).opacity(0.08), in: Capsule())
                .glassEffect(
                    .regular.tint(Color(.systemBackground).opacity(0.12)),
                    in: Capsule()
                )
        } else {
            Text(displayName)
                .font(.headline.weight(.semibold))
                .lineLimit(1)
                .padding(.horizontal, 18)
                .frame(height: 36)
                .background(.ultraThinMaterial, in: Capsule())
        }
    }

    // MARK: - Optimized Content

    @ViewBuilder
    private var metricComparison: some View {
        if previousSnapshot == nil {
            EmptyView()
        } else {
            MetricComparisonCard(
                currentValue: currentTypeCount?.count ?? 0,
                previousValue: previousTypeCount?.count,
                displayName: displayName,
                isCurrentValid: (currentTypeCount?.count ?? 0) >= 0,
                isPreviousTracked: previousTypeCount != nil
            )
        }
    }

    @ViewBuilder
    private var typeEvolutionSection: some View {
        if previousSnapshot != nil {
            TypeEvolutionTimeline(
                snapshots: timelineSnapshots,
                typeIdentifier: typeIdentifier,
                displayName: displayName,
                currentSnapshotID: currentSnapshot.id
            )
        }
    }

    @ViewBuilder
    private var dataRangeSection: some View {
        if currentTypeCount != nil {
            DataTypeRangeIndicator(
                earliestDate: currentTypeCount?.earliestDate,
                latestDate: currentTypeCount?.latestDate,
                quality: currentTypeCount?.quality ?? .complete
            )
        }
    }

    private var recordChangeComparisonSection: some View {
        Group {
            if previousSnapshot != nil {
                switch diffState {
            case .loaded(let diff):
                RecordChangeComparisonCard(
                    displayName: displayName,
                    currentCount: currentTypeCount?.count ?? 0,
                    previousCount: previousTypeCount?.count,
                    addedCount: diff.addedCount,
                    disappearedCount: diff.disappearedCount,
                    isCurrentValid: (currentTypeCount?.count ?? 0) >= 0,
                    isPreviousTracked: previousTypeCount != nil,
                    onAddedTap: {
                        if diff.addedCount > 0 {
                            showAddedRecords = true
                        }
                    },
                    onDisappearedTap: {
                        if diff.disappearedCount > 0 {
                            showDisappearedRecords = true
                        }
                    }
                )
                .navigationDestination(isPresented: $showAddedRecords) {
                    DataTypeRecordListView(
                        title: "Added Records",
                        displayName: displayName,
                        records: diff.addedRecords,
                        totalCount: diff.addedCount,
                        tint: Color.healthyGreen
                    )
                }
                .navigationDestination(isPresented: $showDisappearedRecords) {
                    DataTypeRecordListView(
                        title: "Disappeared Records",
                        displayName: displayName,
                        records: diff.disappearedRecords,
                        totalCount: diff.disappearedCount,
                        tint: Color.criticalRed
                    )
                }

            case .idle:
                VStack(alignment: .leading, spacing: 10) {
                    let quick = quickAddedDisappeared

                    VStack(alignment: .leading, spacing: 8) {
                        Text("Quick Counts")
                            .font(.subheadline.weight(.semibold))

                        HStack {
                            quickStat(label: "Current", value: "\(quickCurrentCountValue)")
                            quickStat(label: "Previous", value: "\(quickPreviousCountValue)")
                        }

                        HStack {
                            quickStat(label: "New", value: "\(quick.added)", color: .healthyGreen)
                            quickStat(label: "Disappeared", value: "\(quick.disappeared)", color: .criticalRed)
                        }

                        if !quick.exact {
                            Text("New/Disappeared are net values from snapshot delta. Exact split needs deep record analysis.")
                                .font(.caption2)
                                .foregroundStyle(.secondary)
                        }
                    }
                    .padding(12)
                    .background(Color(.systemBackground).opacity(0.35), in: RoundedRectangle(cornerRadius: 8))
                }
                .padding(12)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))

            case .unavailable:
                VStack(alignment: .leading, spacing: 8) {
                    Label(
                        "Record detail cache is unavailable for this snapshot pair.",
                        systemImage: "exclamationmark.triangle.fill"
                    )
                    .font(.subheadline)
                    .foregroundStyle(Color.warningAmber)

                    #if DEBUG
                    if let detailCacheDiagnostic {
                        Text(detailCacheDiagnostic)
                            .font(.caption2.monospaced())
                            .foregroundStyle(.secondary)
                            .textSelection(.enabled)
                    }
                    #endif
                }
                .padding(12)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(Color.warningAmber.opacity(0.12), in: RoundedRectangle(cornerRadius: 8))

            case .failed(let message):
                Label(message, systemImage: "exclamationmark.triangle.fill")
                    .font(.subheadline)
                    .foregroundStyle(Color.warningAmber)
                    .padding(12)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .background(Color.warningAmber.opacity(0.12), in: RoundedRectangle(cornerRadius: 8))

            case .loading:
                HStack(spacing: 8) {
                    ProgressView()
                    Text("Analyzing record changes...")
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(12)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
                }
            }
        }
    }

    @ViewBuilder
    private var recordChangeEvolutionSection: some View {
        if previousSnapshot != nil, currentTypeCount != nil {
            RecordChangeEvolutionChart(
                snapshots: timelineSnapshots,
                currentSnapshotID: currentSnapshot.id,
                typeIdentifier: typeIdentifier,
                displayName: displayName
            )
        }
    }

    @ViewBuilder
    private var temporalDistributionSection: some View {
        if previousSnapshot != nil, currentTypeCount != nil, !isCurrentTypeContentAliasToPrevious {
            if !hasTemporalDistributionCache {
                VStack(alignment: .leading, spacing: 8) {
                    Label(
                        "Temporal distribution is available only when precomputed cache exists for this snapshot pair.",
                        systemImage: "info.circle"
                    )
                    .font(.caption)
                    .foregroundStyle(.secondary)
                }
                .padding(12)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
            } else {
            Button {
                showTemporalDistribution = true
            } label: {
                HStack(spacing: 10) {
                    Image(systemName: "chart.bar.xaxis")
                        .font(.system(size: 16, weight: .semibold))
                        .foregroundStyle(.secondary)

                    VStack(alignment: .leading, spacing: 2) {
                        Text("Temporal Distribution")
                            .font(.headline.weight(.semibold))
                            .foregroundStyle(.primary)
                        Text("Added / disappeared by time bucket")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }

                    Spacer()

                    Image(systemName: "chevron.right")
                        .font(.system(size: 12, weight: .semibold))
                        .foregroundStyle(.secondary)
                }
                .padding(12)
                .frame(maxWidth: .infinity, alignment: .leading)
                .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
            }
            .buttonStyle(.plain)
            }
        }
    }

    private func emptyStateContent(_ message: String, icon: String) -> some View {
        VStack(spacing: 12) {
            Image(systemName: icon)
                .font(.system(size: 32, weight: .semibold))
                .foregroundStyle(.secondary)

            Text(message)
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
        }
        .padding(24)
        .frame(maxWidth: .infinity)
        .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))
    }

    private func typeDeltaSummaryText(_ typeDelta: TypeDelta) -> String {
        switch typeDelta.transition {
        case .unchanged:
            return "No metric-level change recorded."
        case .changed:
            if typeDelta.countDelta == 0 {
                return "Content changed while count stayed the same."
            }
            let prefix = typeDelta.countDelta > 0 ? "+" : ""
            return "Count delta: \(prefix)\(typeDelta.countDelta)."
        case .appeared:
            return "Metric appeared in this snapshot."
        case .disappeared:
            return "Metric disappeared in this snapshot."
        }
    }

    private func quickStat(label: String, value: String, color: Color = .primary) -> some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)
            Text(value)
                .font(.subheadline.weight(.semibold).monospacedDigit())
                .foregroundStyle(color)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
    }

    @MainActor
    private func loadRecordDiff() async {
        guard previousSnapshot != nil else {
            detailCacheDiagnostic = nil
            diffState = .loaded(.empty)
            return
        }

        if isCurrentTypeContentAliasToPrevious {
            detailCacheDiagnostic = nil
            diffState = .loaded(.empty)
            return
        }

        let currentCount = currentTypeCount?.count ?? 0
        let previousCount = previousTypeCount?.count ?? 0

        guard currentCount >= 0, previousCount >= 0 else {
            detailCacheDiagnostic = "counts-invalid current=\(currentCount) previous=\(previousCount)"
            diffState = .unavailable
            return
        }

        let resolution = currentDetailCacheResolution()
        detailCacheDiagnostic = resolution?.diagnostic
        guard let cache = resolution?.cache else {
            diffState = .unavailable
            return
        }

        diffState = .loaded(DataTypeRecordDiff(cache: cache))
    }

    @MainActor
    private func currentDetailCacheResolution() -> TypeCountDetailCacheResolution? {
        if isCurrentTypeContentAliasToPrevious {
            return TypeCountDetailCacheResolution(
                cache: nil,
                diagnostic: "alias-to-previous"
            )
        }

        if let cache = currentTypeCount?.detailCache,
           cache.matchesBaseline(previousSnapshot?.id) {
            return TypeCountDetailCacheResolution(
                cache: cache,
                diagnostic: "resolver-v4 phase=cache-hit-view"
            )
        }

        guard let currentTypeCount,
              let previousSnapshot else {
            return nil
        }

        return currentTypeCount.resolveDetailCacheWithDiagnostics(
            previous: previousTypeCount,
            baselineSnapshotID: previousSnapshot.id,
            context: modelContext,
            source: "dataTypeDetail"
        )
    }
}

private struct DataTypeRecordListView: View {
    let title: String
    let displayName: String
    let records: [HealthRecordValue]
    let totalCount: Int
    let tint: Color
    private var showsValueDisclaimer: Bool {
        records.contains { ($0.displayValue?.isEmpty ?? true) }
    }

    var body: some View {
        List {
            Section {
                DataTypeDetailRow(label: "Data Type") {
                    Text(displayName)
                        .foregroundStyle(.secondary)
                        .lineLimit(1)
                }
                DataTypeDetailRow(label: "Records") {
                    Text("\(totalCount)")
                        .foregroundStyle(tint)
                        .monospacedDigit()
                }
                if totalCount > records.count {
                    Text("Showing newest \(records.count) records.")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
                if showsValueDisclaimer {
                    Text("For privacy, HealthProbe stores only timestamps and a record fingerprint here (not the raw HealthKit value).")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }

            Section(title) {
                if records.isEmpty {
                    Text("No records.")
                        .foregroundStyle(.secondary)
                } else {
                    ForEach(records) { record in
                        DataTypeRecordRow(record: record, tint: tint)
                    }
                }
            }
        }
        .navigationTitle(title)
        .navigationBarTitleDisplayMode(.inline)
    }
}

private enum RecordDiffState: Equatable {
    case idle
    case loading
    case unavailable
    case failed(String)
    case loaded(DataTypeRecordDiff)
}

private struct DataTypeRecordDiff: Equatable, Sendable {
    static let previewLimit = 1_000
    static let empty = DataTypeRecordDiff(
        addedCount: 0,
        disappearedCount: 0,
        addedRecords: [],
        disappearedRecords: []
    )

    let addedCount: Int
    let disappearedCount: Int
    let addedRecords: [HealthRecordValue]
    let disappearedRecords: [HealthRecordValue]

    init(
        addedCount: Int,
        disappearedCount: Int,
        addedRecords: [HealthRecordValue],
        disappearedRecords: [HealthRecordValue]
    ) {
        self.addedCount = addedCount
        self.disappearedCount = disappearedCount
        self.addedRecords = addedRecords
        self.disappearedRecords = disappearedRecords
    }

    init(cache: TypeCountDetailCache) {
        self.addedCount = cache.addedCount
        self.disappearedCount = cache.disappearedCount
        self.addedRecords = cache.addedPreviewRecords
        self.disappearedRecords = cache.disappearedPreviewRecords
    }

    var isPreviewLimited: Bool {
        addedCount > Self.previewLimit || disappearedCount > Self.previewLimit
    }
}

private struct DataTypeRecordRow: View {
    let record: HealthRecordValue
    let tint: Color

    var body: some View {
        let recordDate = record.startDate.formatted(.dateTime.year().month().day())
        let startTime = record.startDate.formatted(.dateTime.hour().minute())
        let endTime = record.endDate.formatted(.dateTime.hour().minute())
        let timeRange = (startTime == endTime) ? startTime : "\(startTime)–\(endTime)"

        HStack(spacing: 12) {
            VStack(alignment: .leading, spacing: 2) {
                if let displayValue = record.displayValue, !displayValue.isEmpty {
                    Text(displayValue)
                        .font(.subheadline)
                        .foregroundStyle(.primary)
                } else {
                    Text("No value stored")
                        .font(.subheadline)
                        .foregroundStyle(.secondary)
                }
                Text("\(recordDate) • \(timeRange)")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Spacer()
            if startTime != endTime {
                Text(endTime)
                    .font(.caption)
                    .foregroundStyle(tint)
                    .accessibilityLabel("End \(endTime)")
            }
        }
        .padding(.vertical, 2)
        .accessibilityElement(children: .combine)
    }
}

private struct DataTypeDetailRow<Content: View>: View {
    let label: String
    @ViewBuilder let content: () -> Content

    var body: some View {
        HStack {
            Text(label)
            Spacer()
            content()
        }
    }
}

#Preview {
    NavigationStack {
        DataTypeSnapshotDetailView(
            snapshot: HealthSnapshot(
                timestamp: .now,
                osVersion: "iOS 26.4",
                deviceName: "Preview iPhone",
                deviceID: "preview-device"
            ),
            typeIdentifier: "HKQuantityTypeIdentifierStepCount",
            displayName: "Step Count"
        )
    }
    .modelContainer(for: [HealthSnapshot.self, TypeCount.self, YearlyCount.self, HealthRecord.self, TypeDistributionBin.self], inMemory: true)
}
