import SwiftUI
import SwiftData

struct DataTypesView: View {
    @Environment(AppSettings.self) private var appSettings
    @Query(sort: \HealthSnapshot.timestamp, order: .reverse) private var allSnapshots: [HealthSnapshot]
    @Query private var deviceProfiles: [DeviceProfile]
    @State private var viewModel = DataTypesViewModel()

    private var profileMap: [String: DeviceProfile] {
        Dictionary(uniqueKeysWithValues: deviceProfiles.compactMap {
            $0.deviceID.isEmpty ? nil : ($0.deviceID, $0)
        })
    }

    private var displayedSnapshots: [HealthSnapshot] {
        let selected = appSettings.selectedDeviceIDs
        guard !selected.isEmpty else { return [] }
        return allSnapshots.filter { selected.contains($0.deviceID) }
    }

    private var latest: HealthSnapshot? { displayedSnapshots.first }

    private var knownDevices: [DeviceEntry] {
        let currentID = AppSettings.currentDeviceID
        var ids = Set(allSnapshots.map { $0.deviceID })
        if !currentID.isEmpty { ids.insert(currentID) }
        return ids.map { id in
            let profile = profileMap[id]
            let name: String
            if let n = profile?.name, !n.isEmpty { name = n }
            else if id.isEmpty { name = "Unidentified" }
            else { name = "Unknown Device" }
            let color = DeviceColor(rawValue: profile?.colorTag ?? "")?.color ?? .neutralGray
            return DeviceEntry(id: id, displayName: name, color: color, isCurrent: id == currentID)
        }.sorted {
            if $0.isCurrent != $1.isCurrent { return $0.isCurrent }
            return $0.displayName < $1.displayName
        }
    }

    var body: some View {
        NavigationStack {
            Group {
                if displayedSnapshots.count < 2 {
                    EmptyStateView(
                        icon: "waveform.path.ecg",
                        title: appSettings.selectedDeviceIDs.isEmpty ? "No Devices Selected" : "Not Enough Data",
                        message: appSettings.selectedDeviceIDs.isEmpty
                            ? "Select at least one device using the filter above."
                            : "Create at least two snapshots to compare data types."
                    )
                } else {
                    typeList
                }
            }
            .navigationTitle("Data Types")
            .toolbar { filterPicker }
        }
    }

    // MARK: - List

    private var typeList: some View {
        let diffs = viewModel.diffs(current: latest, snapshots: displayedSnapshots)
        return List {
            comparisonModeHeader
            if diffs.isEmpty {
                Section {
                    Label("No types match the current filter.", systemImage: "magnifyingglass")
                        .foregroundStyle(.secondary)
                        .font(.subheadline)
                }
            } else {
                ForEach(diffs) { diff in
                    NavigationLink(destination: {
                        if let latest = latest {
                            DataTypeSnapshotDetailView(
                                snapshot: latest,
                                typeIdentifier: diff.typeIdentifier,
                                displayName: diff.displayName
                            )
                        }
                    }) {
                        TypeDiffRow(diff: diff)
                    }
                }
            }
        }
    }

    private var comparisonModeHeader: some View {
        Section {
            Picker("Compare Against", selection: $viewModel.comparisonMode) {
                Text("Previous Snapshot").tag(ComparisonMode.previous)
                ForEach(ComparisonMode.relativeOptions, id: \.interval) { opt in
                    Text(opt.label).tag(ComparisonMode.relativeTime(opt.interval))
                }
            }
            .pickerStyle(.menu)
            .accessibilityLabel("Comparison baseline")
        }
    }

    // MARK: - Toolbar

    @ToolbarContentBuilder
    private var filterPicker: some ToolbarContent {
        ToolbarItem(placement: .topBarLeading) {
            devicePickerMenu
        }
        ToolbarItem(placement: .navigationBarTrailing) {
            Menu {
                Picker("Filter", selection: $viewModel.filter) {
                    ForEach(DiffFilter.allCases, id: \.self) { f in
                        Text(f.rawValue).tag(f)
                    }
                }
            } label: {
                Label(viewModel.filter.rawValue, systemImage: "line.3.horizontal.decrease.circle")
                    .labelStyle(.titleAndIcon)
            }
        }
    }

    private var devicePickerMenu: some View {
        let selected = appSettings.selectedDeviceIDs
        let isMulti  = selected.count > 1
        return Menu {
            ForEach(knownDevices) { entry in
                Button {
                    appSettings.toggleDevice(entry.id)
                } label: {
                    Label {
                        Text(entry.isCurrent
                             ? "\(entry.displayName) (This Device)"
                             : entry.displayName)
                    } icon: {
                        Image(systemName: selected.contains(entry.id)
                              ? "checkmark.circle.fill" : "circle.fill")
                            .foregroundStyle(entry.color)
                    }
                }
            }
        } label: {
            Image(systemName: "iphone")
        }
        .tint(isMulti ? .orange : .accentColor)
        .accessibilityLabel("Select devices – \(selected.count) selected")
    }
}

// MARK: - Row

private struct TypeDiffRow: View {
    let diff: TypeDiff

    private var deltaDirection: DeltaIndicator {
        if !diff.previousTracked { return .new }
        if diff.delta > 0 { return .increase }
        if diff.delta < 0 { return .decrease }
        return .stable
    }

    var body: some View {
        HStack(spacing: 12) {
            VStack(alignment: .leading, spacing: 4) {
                Text(diff.displayName)
                    .font(.subheadline.weight(.semibold))
                    .foregroundStyle(.primary)

                HStack(spacing: 12) {
                    metricCompact("Now", diff.currentCount, .accentColor)
                    if diff.previousTracked {
                        metricCompact("Before", diff.previousCount, .secondary)
                    } else {
                        metricCompact("Before", nil, .secondary)
                    }
                }
            }

            Spacer()

            VStack(alignment: .trailing, spacing: 8) {
                deltaIndicatorIcon

                SeverityBadge(delta: diff.previousTracked ? diff.delta : 0, dimmed: !diff.previousTracked)
                    .frame(height: 24)
            }
        }
        .padding(.vertical, 8)
        .accessibilityElement(children: .combine)
        .accessibilityLabel(accessibilityDescription)
    }

    private func metricCompact(_ label: String, _ value: Int?, _ color: Color) -> some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2.weight(.medium))
                .foregroundStyle(.secondary)

            if let value = value {
                Text(value < 0 ? "unavailable" : "\(value)")
                    .font(.caption.weight(.semibold).monospacedDigit())
                    .foregroundStyle(value < 0 ? Color.criticalRed : color)
            } else {
                Text("–")
                    .font(.caption.weight(.semibold).monospacedDigit())
                    .foregroundStyle(.secondary)
            }
        }
    }

    @ViewBuilder
    private var deltaIndicatorIcon: some View {
        switch deltaDirection {
        case .increase:
            Image(systemName: "arrow.up.right")
                .font(.system(size: 14, weight: .semibold))
                .foregroundStyle(Color.healthyGreen)

        case .decrease:
            Image(systemName: "arrow.down.left")
                .font(.system(size: 14, weight: .semibold))
                .foregroundStyle(Color.criticalRed)

        case .stable:
            EmptyView()

        case .new:
            Image(systemName: "sparkles")
                .font(.system(size: 12, weight: .semibold))
                .foregroundStyle(Color.accentColor)
        }
    }

    private var accessibilityDescription: String {
        if diff.previousTracked {
            return "\(diff.displayName). Current: \(diff.currentCount). Previous: \(diff.previousCount). Delta: \(diff.delta)."
        } else {
            return "\(diff.displayName). Current: \(diff.currentCount). New data type in baseline."
        }
    }
}

private enum DeltaIndicator {
    case increase, decrease, stable, new
}

#Preview {
    DataTypesView()
        .modelContainer(for: [HealthSnapshot.self, TypeCount.self, HealthRecord.self, TypeDistributionBin.self, DeviceProfile.self], inMemory: true)
        .environment(AppSettings())
}
