import Charts
import SwiftUI
import SwiftData
import UIKit

struct SnapshotDetailView: View {
    let snapshot: HealthSnapshot
    let baseline: HealthSnapshot?
    let profile: DeviceProfile?

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

    private let diffService = SnapshotDiffService.shared

    private var sortedTypeCounts: [TypeCount] {
        (snapshot.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 deviceDisplayName: String {
        if let name = profile?.name, !name.isEmpty { return name }
        return snapshot.deviceName.isEmpty ? "Unknown device" : snapshot.deviceName
    }

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

    private var evolutionSeries: [TypeEvolutionSeries] {
        sortedTypeCounts.compactMap { typeCount in
            let points = timelineSnapshots.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

    var body: some View {
        List {
            summarySection
            deviceSection
            if let baseline {
                comparisonSection(baseline)
            }
            evolutionSection
            typeCountsSection
        }
        .navigationTitle("Snapshot")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                if isExporting {
                    ProgressView()
                        .accessibilityLabel("Generating PDF")
                } else {
                    Button {
                        exportAsPDF()
                    } label: {
                        Image(systemName: "square.and.arrow.up")
                    }
                    .accessibilityLabel("Export snapshot as PDF")
                }
            }
        }
        .sheet(isPresented: $showShareSheet) {
            if let url = pdfExportURL {
                ShareSheet(items: [url])
                    .ignoresSafeArea()
            }
        }
    }

    private func exportAsPDF() {
        isExporting = true
        let reportData = SnapshotPDFExporter.extractReportData(
            snapshot: snapshot,
            baseline: baseline,
            profile: profile
        )
        let timestamp = snapshot.timestamp
        Task.detached(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)
            await MainActor.run {
                isExporting = false
                pdfExportURL = url
                showShareSheet = true
            }
        }
    }

    private var summarySection: some View {
        Section("Summary") {
            DetailRow(label: "Captured") {
                Text(snapshot.timestamp, format: .dateTime.year().month().day().hour().minute())
                    .foregroundStyle(.secondary)
            }
            DetailRow(label: "Tracked Types") {
                Text("\(sortedTypeCounts.count)")
                    .foregroundStyle(.secondary)
            }
            DetailRow(label: "Total Records") {
                Text("\(totalCount)")
                    .foregroundStyle(.secondary)
                    .monospacedDigit()
            }
        }
    }

    private var deviceSection: some View {
        Section("Device") {
            DetailRow(label: "Name") {
                Text(deviceDisplayName)
                    .foregroundStyle(.secondary)
            }
            DetailRow(label: "OS") {
                Text(snapshot.osVersion)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private func comparisonSection(_ baseline: HealthSnapshot) -> some View {
        Section("Comparison") {
            DetailRow(label: "Baseline") {
                Text(baseline.timestamp, format: .dateTime.year().month().day().hour().minute())
                    .foregroundStyle(.secondary)
            }
            DetailRow(label: "Changes") {
                let delta = diffService.totalAbsoluteChange(current: snapshot, baseline: baseline)
                Text(delta == 0 ? "None" : "\(delta) records")
                    .foregroundStyle(delta == 0 ? Color.healthyGreen : Color.warningAmber)
            }
        }
    }

    private var evolutionSection: some View {
        Section("Evolution") {
            if evolutionSeries.isEmpty {
                Text("No chartable data for this snapshot.")
                    .foregroundStyle(.secondary)
            } else {
                ForEach(evolutionSeries) { series in
                    TypeEvolutionChart(
                        series: series,
                        selectedSnapshotID: snapshot.id
                    )
                }
            }
        }
    }

    private var typeCountsSection: some View {
        Section("Data Types") {
            if sortedTypeCounts.isEmpty {
                Text("No tracked data types in this snapshot.")
                .foregroundStyle(.secondary)
            } else {
                ForEach(sortedTypeCounts) { typeCount in
                    SnapshotTypeCountRow(
                        typeCount: typeCount,
                        baselineTypeCount: baselineTypeMap[typeCount.typeIdentifier]
                    )
                }
            }
        }
    }
}

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 selectedSnapshotID: UUID

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

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

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

                    if point.snapshotID == selectedSnapshotID {
                        PointMark(
                            x: .value("Selected Date", point.timestamp),
                            y: .value("Selected Records", point.count)
                        )
                        .symbolSize(64)
                    }
                }
            }
            .chartYScale(domain: series.yDomain)
            .chartXAxis {
                AxisMarks(values: .automatic(desiredCount: 3))
            }
            .chartYAxis {
                AxisMarks(position: .leading, values: .automatic(desiredCount: 3))
            }
            .frame(height: 120)
            .foregroundStyle(Color.accentColor)

            if series.points.count == 1 {
                Text("Only one measurement")
                    .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
    }

    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 let delta {
                    SeverityBadge(delta: delta)
                }
            }
        }
        .accessibilityElement(children: .combine)
    }
}

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, DeviceProfile.self], inMemory: true)
}
