import Charts
import SwiftUI
import SwiftData
import UIKit

struct SnapshotDetailView: View {
    let snapshot: HealthSnapshot
    let baseline: HealthSnapshot?
    let profile: DeviceProfile?
    private let contextRadius = 3

    @Query(sort: \HealthSnapshot.timestamp) private var allSnapshots: [HealthSnapshot]

    private let diffService = SnapshotDiffService.shared

    @State private var xAxisMode: EvolutionXAxisMode = .snapshots
    @State private var displayedSnapshot: HealthSnapshot?

    private var currentSnapshot: HealthSnapshot {
        displayedSnapshot ?? snapshot
    }

    private var sortedTypeCounts: [TypeCount] {
        (currentSnapshot.typeCounts ?? []).sorted {
            $0.displayName.localizedCompare($1.displayName) == .orderedAscending
        }
    }

    private var baselineTypeMap: [String: TypeCount] {
        Dictionary(
            uniqueKeysWithValues: (baseline?.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )
    }

    private var totalCount: Int {
        sortedTypeCounts.reduce(0) { partial, typeCount in
            typeCount.count > 0 ? partial + typeCount.count : partial
        }
    }

    private var snapshotEarliestRecordDate: Date? {
        sortedTypeCounts
            .filter { !$0.isUnsupported && $0.count > 0 }
            .compactMap(\.earliestDate)
            .min()
    }

    private var snapshotNewestRecordDate: Date? {
        sortedTypeCounts
            .filter { !$0.isUnsupported && $0.count > 0 }
            .compactMap(\.latestDate)
            .max()
    }

    private var deviceDisplayName: String {
        if let name = profile?.name, !name.isEmpty { return name }
        return currentSnapshot.deviceName.isEmpty ? "Unknown device" : currentSnapshot.deviceName
    }

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

    private var timelineContextSnapshots: [HealthSnapshot] {
        guard let currentIndex = timelineSnapshots.firstIndex(where: { $0.id == currentSnapshot.id }) else {
            return [currentSnapshot]
        }

        let desiredCount = contextRadius * 2 + 1
        var start = max(0, currentIndex - contextRadius)
        var end = min(timelineSnapshots.count - 1, currentIndex + contextRadius)

        let currentCount = end - start + 1
        if currentCount < desiredCount {
            let missing = desiredCount - currentCount

            let extraBefore = min(start, missing)
            start -= extraBefore

            let remaining = missing - extraBefore
            let availableAfter = timelineSnapshots.count - 1 - end
            let extraAfter = min(availableAfter, remaining)
            end += extraAfter

            if extraAfter < remaining {
                let finalRemaining = remaining - extraAfter
                let availableBefore = start
                let finalExtraBefore = min(availableBefore, finalRemaining)
                start -= finalExtraBefore
            }
        }

        return Array(timelineSnapshots[start...end])
    }

    private var isTimelineContextTrimmed: Bool {
        timelineContextSnapshots.count < timelineSnapshots.count
    }

    private var timelineSnapshotNumbers: [UUID: Int] {
        Dictionary(
            uniqueKeysWithValues: timelineSnapshots.enumerated().map { index, snapshot in
                (snapshot.id, index + 1)
            }
        )
    }

    private var currentSnapshotIndex: Int? {
        timelineSnapshots.firstIndex(where: { $0.id == currentSnapshot.id })
    }

    private var previousSnapshot: HealthSnapshot? {
        guard let currentIndex = currentSnapshotIndex, currentIndex > 0 else { return nil }
        return timelineSnapshots[currentIndex - 1]
    }

    private var nextSnapshot: HealthSnapshot? {
        guard let currentIndex = currentSnapshotIndex, currentIndex < timelineSnapshots.count - 1 else { return nil }
        return timelineSnapshots[currentIndex + 1]
    }

    private var evolutionSeries: [TypeEvolutionSeries] {
        sortedTypeCounts.compactMap { typeCount in
            let points = timelineContextSnapshots.compactMap { candidate -> TypeEvolutionPoint? in
                guard let candidateTypeCount = candidate.typeCounts?.first(where: {
                    $0.typeIdentifier == typeCount.typeIdentifier
                }),
                      candidateTypeCount.count >= 0
                else {
                    return nil
                }

                return TypeEvolutionPoint(
                    snapshotID: candidate.id,
                    timestamp: candidate.timestamp,
                    count: candidateTypeCount.count
                )
            }

            guard !points.isEmpty else { return nil }
            return TypeEvolutionSeries(
                typeIdentifier: typeCount.typeIdentifier,
                displayName: typeCount.displayName,
                points: points
            )
        }
    }

    @State private var showShareSheet = false
    @State private var pdfExportURL: URL?
    @State private var isExporting = false
    @State private var showMetadataSheet = false

    var body: some View {
        List {
            evolutionSection
        }
        .navigationTitle("Snapshot")
        .navigationBarTitleDisplayMode(.inline)
        .safeAreaInset(edge: .top, spacing: 0) {
            snapshotNavigationHeader
                .frame(height: 64)
        }
        .toolbar {
            ToolbarItem(placement: .principal) {
                snapshotToolbarTitle
            }
            ToolbarItem(placement: .navigationBarTrailing) {
                HStack(spacing: 12) {
                    Button {
                        showMetadataSheet = true
                    } label: {
                        Image(systemName: "info.circle")
                    }
                    .accessibilityLabel("View snapshot details")

                    if isExporting {
                        ProgressView()
                            .accessibilityLabel("Generating PDF")
                    } else {
                        Button {
                            exportAsPDF()
                        } label: {
                            Image(systemName: "square.and.arrow.up")
                        }
                        .accessibilityLabel("Export snapshot as PDF")
                    }
                }
            }
        }
        .sheet(isPresented: $showMetadataSheet) {
            metadataSheetContent
        }
        .sheet(isPresented: $showShareSheet) {
            if let url = pdfExportURL {
                ShareSheet(items: [url])
                    .ignoresSafeArea()
            }
        }
    }

    private func exportAsPDF() {
        isExporting = true
        let reportData = SnapshotPDFExporter.extractReportData(
            snapshot: currentSnapshot,
            baseline: baseline,
            profile: profile
        )
        let timestamp = currentSnapshot.timestamp
        Task(priority: .userInitiated) {
            let pdfData = SnapshotPDFExporter.generatePDF(from: reportData)
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd-HH-mm"
            let name = "HealthProbe-Snapshot-\(formatter.string(from: timestamp)).pdf"
            let url = FileManager.default.temporaryDirectory.appendingPathComponent(name)
            try? pdfData.write(to: url)
            isExporting = false
            pdfExportURL = url
            showShareSheet = true
        }
    }

    @ViewBuilder
    private var snapshotToolbarTitle: some View {
        if #available(iOS 26.0, *) {
            Text("Snapshot")
                .font(.headline.weight(.semibold))
                .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(currentSnapshot.timestamp, format: .dateTime.month().day().hour().minute())
                .font(.headline.weight(.semibold))
                .padding(.horizontal, 18)
                .frame(height: 36)
                .background(.ultraThinMaterial, in: Capsule())
        }
    }

    @ViewBuilder
    private var snapshotNavigationHeader: some View {
        if #available(iOS 26.0, *) {
            GlassEffectContainer(spacing: 10) {
                snapshotNavigationHeaderContent
                    .padding(.horizontal, 12)
                    .frame(height: 52)
                    .background(Color(.systemBackground).opacity(0.08), in: Capsule())
                    .glassEffect(
                        .regular.tint(Color(.systemBackground).opacity(0.14)),
                        in: Capsule()
                    )
                    .shadow(color: .black.opacity(0.18), radius: 18, x: 0, y: 8)
            }
            .padding(.horizontal, 12)
            .padding(.vertical, 6)
        } else {
            snapshotNavigationHeaderContent
                .padding(.horizontal, 12)
                .frame(height: 52)
                .background(.ultraThinMaterial, in: Capsule())
                .overlay(
                    Capsule()
                        .strokeBorder(Color.primary.opacity(0.08), lineWidth: 1)
                )
                .shadow(color: .black.opacity(0.14), radius: 16, x: 0, y: 8)
                .padding(.horizontal, 12)
                .padding(.vertical, 6)
        }
    }

    private var snapshotNavigationHeaderContent: some View {
        HStack(spacing: 12) {
            snapshotNavigationButton(
                systemName: "chevron.left",
                label: "Prev",
                target: previousSnapshot,
                accessibilityLabel: "Previous snapshot"
            )

            Spacer(minLength: 8)

            Menu {
                ForEach(timelineSnapshots) { candidate in
                    Button {
                        displayedSnapshot = candidate
                    } label: {
                        if candidate.id == currentSnapshot.id {
                            Label(
                                candidate.timestamp.formatted(.dateTime.year().month().day().hour().minute()),
                                systemImage: "checkmark"
                            )
                        } else {
                            Text(candidate.timestamp, format: .dateTime.year().month().day().hour().minute())
                        }
                    }
                }
            } label: {
                VStack(spacing: 2) {
                    Text(currentSnapshot.timestamp, format: .dateTime.month().day().hour().minute())
                        .font(.headline.weight(.semibold))
                }
            }
            .buttonStyle(.plain)
            .lineLimit(1)
            .accessibilityLabel("Select current snapshot")

            Spacer(minLength: 8)

            snapshotNavigationButton(
                systemName: "chevron.right",
                label: "Next",
                target: nextSnapshot,
                accessibilityLabel: "Next snapshot"
            )
        }
    }

    @ViewBuilder
    private func snapshotNavigationButton(
        systemName: String,
        label: String,
        target: HealthSnapshot?,
        accessibilityLabel: String
    ) -> some View {
        if let target {
            Button {
                displayedSnapshot = target
            } label: {
                VStack(spacing: 2) {
                    Image(systemName: systemName)
                        .font(.system(size: 23, weight: .regular))
                        .symbolRenderingMode(.hierarchical)
                    Text(label)
                        .font(.caption2.weight(.medium))
                        .lineLimit(1)
                }
                .frame(width: 70, height: 50)
                .contentShape(Rectangle())
            }
            .buttonStyle(.plain)
            .foregroundStyle(Color.primary)
            .accessibilityLabel(accessibilityLabel)
        } else {
            Color.clear
                .frame(width: 70, height: 50)
        }
    }

    @ViewBuilder
    private var metadataSheetContent: some View {
        NavigationStack {
            ScrollView {
                VStack(alignment: .leading, spacing: 12) {
                    // Title with Date
                    VStack(spacing: 4) {
                        Text("Snapshot")
                            .font(.headline.weight(.semibold))
                        Text(currentSnapshot.timestamp, format: .dateTime.month().day().hour().minute())
                            .font(.subheadline)
                            .foregroundStyle(.secondary)
                    }
                    .frame(maxWidth: .infinity, alignment: .center)
                    .padding(12)
                    .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))

                    // Data Range
                    SnapshotDataRangeIndicator(
                        oldestRecordDate: snapshotEarliestRecordDate,
                        newestRecordDate: snapshotNewestRecordDate,
                        quality: currentSnapshot.snapshotQuality
                    )

                    // Summary Stats (compact)
                    VStack(spacing: 12) {
                        HStack(spacing: 16) {
                            statCompact(label: "Types", value: "\(sortedTypeCounts.count)")
                            Divider()
                            statCompact(label: "Records", value: "\(totalCount)")
                        }
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    }
                    .padding(12)
                    .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))

                    // Device (collapsible)
                    DisclosureGroup {
                        VStack(alignment: .leading, spacing: 12) {
                            DetailRow(label: "Version") {
                                Text(extractOSVersion(currentSnapshot.osVersion))
                                    .foregroundStyle(.secondary)
                                    .font(.caption.monospacedDigit())
                            }
                            Divider()
                            DetailRow(label: "Build") {
                                Text(extractBuildNumber(currentSnapshot.osVersion))
                                    .foregroundStyle(.secondary)
                                    .font(.caption.monospacedDigit())
                            }
                        }
                        .padding(.top, 8)
                    } label: {
                        HStack(spacing: 8) {
                            Image(systemName: "iphone")
                                .font(.system(size: 16, weight: .semibold))
                            Text(deviceDisplayName)
                                .font(.subheadline.weight(.semibold))
                        }
                    }
                    .padding(12)
                    .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))

                    // Comparison (if baseline exists)
                    if let baseline {
                        comparisonSection(baseline: baseline)
                    }

                    Spacer()
                }
                .padding(16)
            }
            .navigationTitle("Snapshot")
            .navigationBarTitleDisplayMode(.inline)
        }
    }

    @ViewBuilder
    private func comparisonSection(baseline: HealthSnapshot) -> some View {
        let delta = diffService.totalAbsoluteChange(current: currentSnapshot, baseline: baseline)
        let deltaPercent = computeDeltaPercent(delta: delta, baseline: baseline)
        let isSignificant = delta > 0 || (deltaPercent > 10)

        DisclosureGroup {
            VStack(alignment: .leading, spacing: 12) {
                DetailRow(label: "Baseline") {
                    Text(baseline.timestamp, format: .dateTime.month().day().hour().minute())
                        .foregroundStyle(.secondary)
                }
                Divider()
                DetailRow(label: "Time Span") {
                    let days = Calendar.current.dateComponents([.day], from: baseline.timestamp, to: currentSnapshot.timestamp).day ?? 0
                    Text(days == 0 ? "Same day" : "\(days) days")
                        .foregroundStyle(.secondary)
                }
            }
            .padding(.top, 8)
        } label: {
            HStack(spacing: 8) {
                Image(systemName: "arrow.left.and.right.square")
                    .font(.system(size: 16, weight: .semibold))
                Text("Comparison")
                    .font(.subheadline.weight(.semibold))
                Spacer()
                if isSignificant {
                    SeverityBadge(delta: delta)
                        .frame(height: 24)
                } else {
                    Text("–")
                        .font(.caption2.weight(.semibold))
                        .foregroundStyle(.secondary)
                }
            }
        }
        .padding(12)
        .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))
    }

    private func shortOSVersion(_ full: String) -> Text {
        if full.hasPrefix("iOS ") {
            let version = full.dropFirst(4).prefix(while: { $0 != " " })
            return Text("iOS \(version)")
        }
        return Text(full)
    }

    private func extractOSVersion(_ full: String) -> String {
        if full.hasPrefix("iOS ") {
            let versionPart = full.dropFirst(4).prefix(while: { $0 != " " && $0 != "(" })
            return String(versionPart)
        }
        return full
    }
    
    private func extractBuildNumber(_ full: String) -> String {
        if let start = full.firstIndex(of: "("), let end = full.firstIndex(of: ")") {
            let buildPart = String(full[full.index(after: start)..<end])
            return buildPart.hasPrefix("Build ") ? String(buildPart.dropFirst(6)) : buildPart
        }
        return full
    }

    private func computeDeltaPercent(delta: Int, baseline: HealthSnapshot) -> Double {
        let baselineTotal = (baseline.typeCounts ?? [])
            .filter { $0.count > 0 }
            .reduce(0) { $0 + $1.count }
        return baselineTotal > 0 ? Double(delta) / Double(baselineTotal) * 100 : 0
    }

    private func statCompact(label: String, value: String) -> some View {
        VStack(alignment: .center, spacing: 2) {
            Text(label)
                .font(.caption2.weight(.medium))
            Text(value)
                .font(.subheadline.weight(.semibold).monospacedDigit())
                .foregroundStyle(.primary)
        }
        .frame(maxWidth: .infinity)
    }

    private var evolutionSection: some View {
        Section("Data Types") {
            HStack {
                Spacer()
                Picker("X-Axis", selection: $xAxisMode) {
                    ForEach(EvolutionXAxisMode.allCases.reversed()) { mode in
                        Text(mode.title).tag(mode)
                    }
                }
                .pickerStyle(.segmented)
                Spacer()
            }

            if evolutionSeries.isEmpty {
                if sortedTypeCounts.isEmpty {
                    Text("No tracked data types in this snapshot.")
                        .foregroundStyle(.secondary)
                } else {
                    ForEach(sortedTypeCounts) { typeCount in
                        NavigationLink {
                            DataTypeSnapshotDetailView(
                                snapshot: currentSnapshot,
                                typeIdentifier: typeCount.typeIdentifier,
                                displayName: typeCount.displayName
                            )
                        } label: {
                            SnapshotTypeCountRow(
                                typeCount: typeCount,
                                baselineTypeCount: baselineTypeMap[typeCount.typeIdentifier]
                            )
                        }
                    }
                }
            } else {
                ForEach(evolutionSeries) { series in
                    NavigationLink {
                        DataTypeSnapshotDetailView(
                            snapshot: currentSnapshot,
                            typeIdentifier: series.typeIdentifier,
                            displayName: series.displayName
                        )
                    } label: {
                        TypeEvolutionChart(
                            series: series,
                            contextSnapshots: timelineContextSnapshots,
                            xAxisMode: xAxisMode,
                            selectedSnapshotID: currentSnapshot.id,
                            selectedTimestamp: currentSnapshot.timestamp,
                            snapshotNumbers: timelineSnapshotNumbers,
                            baselineTypeCount: baselineTypeMap[series.typeIdentifier]
                        )
                    }
                }

                if isTimelineContextTrimmed {
                    Text("Charts show only the local window: 3 snapshots before and 3 after the current one.")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
        }
    }
}

private enum EvolutionXAxisMode: String, CaseIterable, Identifiable {
    case time
    case snapshots

    var id: String { rawValue }

    var title: String {
        switch self {
        case .time:
            return "Time"
        case .snapshots:
            return "Snapshots"
        }
    }
}

private struct TypeEvolutionSeries: Identifiable {
    let typeIdentifier: String
    let displayName: String
    let points: [TypeEvolutionPoint]

    var id: String { typeIdentifier }

    var latestPoint: TypeEvolutionPoint? {
        points.max { $0.timestamp < $1.timestamp }
    }

    var selectedOrLatestPoint: TypeEvolutionPoint? {
        points.last
    }

    var yDomain: ClosedRange<Double> {
        let counts = points.map(\.count)
        guard let minCount = counts.min(), let maxCount = counts.max() else {
            return 0...1
        }

        if minCount == maxCount {
            let lower = max(0, minCount - 1)
            return Double(lower)...Double(maxCount + 1)
        }

        return Double(max(0, minCount))...Double(maxCount)
    }
}

private struct TypeEvolutionPoint: Identifiable {
    let snapshotID: UUID
    let timestamp: Date
    let count: Int

    var id: UUID { snapshotID }
}

private struct TypeEvolutionChart: View {
    let series: TypeEvolutionSeries
    let contextSnapshots: [HealthSnapshot]
    let xAxisMode: EvolutionXAxisMode
    let selectedSnapshotID: UUID
    let selectedTimestamp: Date
    let snapshotNumbers: [UUID: Int]
    let baselineTypeCount: TypeCount?

    private struct SnapshotAxisPoint: Identifiable {
        let snapshotID: UUID
        let contextIndex: Int
        let timestamp: Date
        let count: Int

        var id: UUID { snapshotID }
    }

    private var selectedPoint: TypeEvolutionPoint? {
        series.points.first { $0.snapshotID == selectedSnapshotID }
    }

    private var isMissingInSelectedSnapshot: Bool {
        selectedPoint == nil
    }

    private var previousPoint: TypeEvolutionPoint? {
        guard let selectedIndex = series.points.firstIndex(where: { $0.snapshotID == selectedSnapshotID }),
              selectedIndex > 0 else { return nil }
        return series.points[selectedIndex - 1]
    }

    private var delta: Int? {
        guard let selected = selectedPoint,
              let previous = previousPoint,
              selected.count >= 0,
              previous.count >= 0 else { return nil }
        return selected.count - previous.count
    }

    private var isSignificantChange: Bool {
        guard let d = delta, let prev = previousPoint?.count, prev > 0 else { return false }
        let percentChange = abs(Double(d)) / Double(prev) * 100
        return percentChange > 10 || d > 0
    }

    private var contextPointCountLabel: String {
        "\(series.points.count)/\(contextSnapshots.count) snapshots with data"
    }

    private var contextAxisPoints: [SnapshotAxisPoint] {
        contextSnapshots.enumerated().compactMap { index, snapshot in
            guard let candidateTypeCount = snapshot.typeCounts?.first(where: {
                $0.typeIdentifier == series.typeIdentifier
            }), candidateTypeCount.count >= 0 else {
                return nil
            }

            return SnapshotAxisPoint(
                snapshotID: snapshot.id,
                contextIndex: index,
                timestamp: snapshot.timestamp,
                count: candidateTypeCount.count
            )
        }
    }

    private var contextAxisGroups: [[SnapshotAxisPoint]] {
        guard !contextAxisPoints.isEmpty else { return [] }

        var groups: [[SnapshotAxisPoint]] = []
        var currentGroup: [SnapshotAxisPoint] = [contextAxisPoints[0]]

        for point in contextAxisPoints.dropFirst() {
            if let previous = currentGroup.last, point.contextIndex == previous.contextIndex + 1 {
                currentGroup.append(point)
            } else {
                groups.append(currentGroup)
                currentGroup = [point]
            }
        }

        groups.append(currentGroup)
        return groups
    }

    private var selectedContextIndex: Int? {
        contextSnapshots.firstIndex { $0.id == selectedSnapshotID }
    }

    private var snapshotAxisValues: [Int] {
        Array(contextSnapshots.indices)
    }

    private func snapshotAxisLabel(for index: Int) -> String {
        guard contextSnapshots.indices.contains(index) else { return "\(index + 1)" }
        let snapshotID = contextSnapshots[index].id
        return "\(snapshotNumbers[snapshotID] ?? index + 1)"
    }

    private var snapshotAxisDomain: ClosedRange<Int> {
        guard let first = snapshotAxisValues.first, let last = snapshotAxisValues.last else {
            return 0...0
        }
        return first...last
    }

    @ViewBuilder
    private var chartContent: some View {
        switch xAxisMode {
        case .time:
            timeChart
        case .snapshots:
            snapshotChart
        }
    }

    private var timeChart: some View {
        Chart {
            ForEach(contextSnapshots, id: \.id) { item in
                RuleMark(x: .value("Timeline", item.timestamp))
                    .foregroundStyle(Color.secondary.opacity(0.10))
            }

            RuleMark(x: .value("Selected Snapshot", selectedTimestamp))
                .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 3]))
                .foregroundStyle(Color.secondary.opacity(0.55))

            ForEach(series.points) { point in
                LineMark(
                    x: .value("Date", point.timestamp),
                    y: .value("Records", point.count)
                )
                .interpolationMethod(.linear)

                PointMark(
                    x: .value("Date", point.timestamp),
                    y: .value("Records", point.count)
                )
                .symbolSize(24)

                if point.snapshotID == selectedSnapshotID {
                    PointMark(
                        x: .value("Selected Date", point.timestamp),
                        y: .value("Selected Records", point.count)
                    )
                    .symbolSize(64)
                }
            }
        }
    }

    private var snapshotChart: some View {
        Chart {
            ForEach(contextSnapshots.indices, id: \.self) { index in
                RuleMark(x: .value("Snapshot", index))
                    .foregroundStyle(Color.secondary.opacity(0.10))
            }

            if let selectedContextIndex {
                RuleMark(x: .value("Selected Snapshot", selectedContextIndex))
                    .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 3]))
                    .foregroundStyle(Color.secondary.opacity(0.55))
            }

            ForEach(contextAxisGroups.indices, id: \.self) { groupIndex in
                let group = contextAxisGroups[groupIndex]

                ForEach(group) { point in
                    LineMark(
                        x: .value("Snapshot", point.contextIndex),
                        y: .value("Records", point.count)
                    )
                    .interpolationMethod(.linear)

                    PointMark(
                        x: .value("Snapshot", point.contextIndex),
                        y: .value("Records", point.count)
                    )
                    .symbolSize(24)

                    if point.snapshotID == selectedSnapshotID {
                        PointMark(
                            x: .value("Selected Snapshot", point.contextIndex),
                            y: .value("Selected Records", point.count)
                        )
                        .symbolSize(64)
                    }
                }
            }
        }
        .chartXAxis {
            AxisMarks(values: snapshotAxisValues) { value in
                AxisGridLine()
                AxisTick()
                if let rawIndex = value.as(Int.self) {
                    AxisValueLabel(snapshotAxisLabel(for: rawIndex))
                }
            }
        }
        .chartXScale(domain: snapshotAxisDomain)
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack(alignment: .firstTextBaseline) {
                Text(series.displayName)
                    .font(.subheadline.weight(.semibold))
                Spacer()
                VStack(alignment: .trailing, spacing: 4) {
                    if let selectedPoint {
                        Text("\(selectedPoint.count)")
                            .font(.subheadline.monospacedDigit())
                            .foregroundStyle(.secondary)
                    }
                    if isSignificantChange, let delta {
                        SeverityBadge(delta: delta)
                    }
                }
            }

            chartContent
            .chartYScale(domain: series.yDomain)
            .chartXAxis {
                switch xAxisMode {
                case .time:
                    AxisMarks(values: .automatic(desiredCount: 3))
                case .snapshots:
                    AxisMarks(values: snapshotAxisValues) { value in
                        AxisGridLine()
                        AxisTick()
                        if let rawIndex = value.as(Int.self) {
                            AxisValueLabel(snapshotAxisLabel(for: rawIndex))
                        }
                    }
                }
            }
            .chartYAxis {
                AxisMarks(position: .leading, values: .automatic(desiredCount: 3))
            }
            .frame(height: 120)
            .foregroundStyle(Color.accentColor)

            if isMissingInSelectedSnapshot {
                Text("Datatype missing in this snapshot")
                    .font(.caption2)
                    .foregroundStyle(Color.warningAmber)
            } else if series.points.count == 1 {
                Text("Only one measurement")
                    .font(.caption2)
                    .foregroundStyle(.secondary)
            }

            Text(contextPointCountLabel)
                .font(.caption2)
                .foregroundStyle(.secondary)
        }
        .padding(.vertical, 4)
        .accessibilityElement(children: .combine)
    }
}

private struct SnapshotTypeCountRow: View {
    let typeCount: TypeCount
    let baselineTypeCount: TypeCount?

    private var countText: String {
        if typeCount.isUnsupported { return "Unsupported" }
        if typeCount.count == -1   { return "Unavailable" }
        return "\(typeCount.count)"
    }

    private var countColor: Color {
        if typeCount.isUnsupported { return .secondary }
        if typeCount.count == -1   { return Color.criticalRed }
        if typeCount.quality != SnapshotQuality.complete { return Color.warningAmber }
        return Color.primary
    }

    private var delta: Int? {
        guard let b = baselineTypeCount,
              typeCount.count >= 0,
              b.count >= 0 else { return nil }
        return typeCount.count - b.count
    }

    private var isSignificantChange: Bool {
        guard let d = delta, let b = baselineTypeCount?.count, b > 0 else { return false }
        let percentChange = abs(Double(d)) / Double(b) * 100
        return percentChange > 10 || d > 0
    }

    var body: some View {
        HStack(spacing: 12) {
            VStack(alignment: .leading, spacing: 3) {
                Text(typeCount.displayName)
                    .font(.subheadline)
                Text(typeCount.typeIdentifier)
                    .font(.caption2)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
                    .truncationMode(.middle)
            }
            Spacer()
            VStack(alignment: .trailing, spacing: 4) {
                Text(countText)
                    .font(.subheadline.monospacedDigit())
                    .foregroundStyle(countColor)
                if isSignificantChange, let delta {
                    SeverityBadge(delta: delta)
                }
            }
        }
        .accessibilityElement(children: .combine)
    }
}

private struct SnapshotDataRangeIndicator: View {
    let oldestRecordDate: Date?
    let newestRecordDate: Date?
    let quality: SnapshotQuality

    private var hasDateRange: Bool {
        oldestRecordDate != nil && newestRecordDate != nil
    }

    private var daySpan: Int? {
        guard let oldest = oldestRecordDate, let newest = newestRecordDate else { return nil }
        return Calendar.current.dateComponents([.day], from: oldest, to: newest).day ?? 0
    }

    var body: some View {
        VStack(spacing: 12) {
            HStack(spacing: 8) {
                Text("Data Range")
                    .font(.headline.weight(.semibold))

                Spacer()

                qualityBadge
            }

            if hasDateRange {
                dateRangeVisualization
            } else {
                Text("No dated records available")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
                    .frame(maxWidth: .infinity, alignment: .center)
                    .padding(.vertical, 16)
            }
        }
        .padding(16)
        .background(Color(.systemBackground).opacity(0.5), in: RoundedRectangle(cornerRadius: 12))
    }

    @ViewBuilder
    private var qualityBadge: some View {
        if quality != .complete {
            Label("Incomplete", systemImage: "exclamationmark.triangle.fill")
                .font(.caption.weight(.medium))
                .foregroundStyle(Color.warningAmber)
                .padding(.horizontal, 8)
                .padding(.vertical, 4)
                .background(Color.warningAmber.opacity(0.12), in: Capsule())
        }
    }

    @ViewBuilder
    private var dateRangeVisualization: some View {
        if let oldest = oldestRecordDate, let newest = newestRecordDate, let span = daySpan {
            VStack(spacing: 12) {
                HStack(alignment: .top, spacing: 12) {
                    VStack(alignment: .center, spacing: 4) {
                        Image(systemName: "calendar.badge.clock")
                            .font(.system(size: 16, weight: .semibold))
                            .foregroundStyle(Color.healthyGreen)

                        VStack(alignment: .center, spacing: 2) {
                            Text("Oldest record")
                                .font(.caption2.weight(.medium))
                                .foregroundStyle(.secondary)
                            Text(oldest, format: .dateTime.month().day().year())
                                .font(.caption.weight(.semibold))
                        }
                    }
                    .frame(maxWidth: .infinity)

                    VStack(alignment: .center, spacing: 4) {
                        Text("\(span)")
                            .font(.system(size: 18, weight: .semibold).monospacedDigit())
                            .foregroundStyle(.primary)

                        Text("days")
                            .font(.caption2.weight(.medium))
                            .foregroundStyle(.secondary)
                    }

                    VStack(alignment: .center, spacing: 4) {
                        Image(systemName: "calendar.badge.clock")
                            .font(.system(size: 16, weight: .semibold))
                            .foregroundStyle(Color.accentColor)

                        VStack(alignment: .center, spacing: 2) {
                            Text("Newest record")
                                .font(.caption2.weight(.medium))
                                .foregroundStyle(.secondary)
                            Text(newest, format: .dateTime.month().day().year())
                                .font(.caption.weight(.semibold))
                        }
                    }
                    .frame(maxWidth: .infinity)
                }

                timelineBar
            }
        }
    }

    @ViewBuilder
    private var timelineBar: some View {
        if oldestRecordDate != nil, newestRecordDate != nil {
            ZStack(alignment: .leading) {
                RoundedRectangle(cornerRadius: 3)
                    .fill(Color(.systemGray5))

                RoundedRectangle(cornerRadius: 3)
                    .fill(
                        LinearGradient(
                            gradient: Gradient(colors: [Color.healthyGreen, Color.accentColor]),
                            startPoint: .leading,
                            endPoint: .trailing
                        )
                    )
                    .opacity(0.7)
            }
            .frame(height: 4)
        }
    }
}

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

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

private struct ShareSheet: UIViewControllerRepresentable {
    let items: [Any]

    func makeUIViewController(context: Context) -> UIActivityViewController {
        UIActivityViewController(activityItems: items, applicationActivities: nil)
    }

    func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {}
}

#Preview {
    NavigationStack {
        SnapshotDetailView(
            snapshot: HealthSnapshot(
                timestamp: .now,
                osVersion: "iOS 26.4",
                deviceName: "Preview iPhone",
                deviceID: "preview-device"
            ),
            baseline: nil,
            profile: DeviceProfile(deviceID: "preview-device")
        )
    }
    .modelContainer(for: [HealthSnapshot.self, TypeCount.self, YearlyCount.self, HealthRecord.self, TypeDistributionBin.self, DeviceProfile.self], inMemory: true)
}
