import SwiftUI

struct SnapshotsView: View {
    @State private var viewModel = SnapshotsViewModel()

    private var archiveRows: [CachedArchiveObservationRow] {
        viewModel.archiveRows ?? []
    }

    private var hasTimelineRows: Bool {
        !archiveRows.isEmpty
    }

    private var snapshotItems: [SnapshotListItem] {
        let baselines = viewModel.baselines(for: archiveRows)
        return archiveRows.map { row in
            SnapshotListItem(
                archiveRow: row,
                baseline: baselines[row.observationID],
                showsDeltaSummary: viewModel.comparisonMode == .previous
            )
        }
    }

    var body: some View {
        NavigationStack {
            Group {
                if !viewModel.hasLoadedArchiveRows {
                    ContentUnavailableView {
                        Label("Loading snapshots", systemImage: "clock.arrow.circlepath")
                    }
                } else if !hasTimelineRows {
                    EmptyStateView(
                        icon: "clock.arrow.circlepath",
                        title: "No Snapshots",
                        message: "Use the Dashboard to create your first local snapshot."
                    )
                } else {
                    snapshotList
                }
            }
            .navigationTitle("Snapshots")
            .toolbar { toolbarContent }
            .task {
                await viewModel.loadArchiveRows()
            }
        }
    }

    private var snapshotList: some View {
        List(snapshotItems) { item in
            NavigationLink {
                SnapshotArchiveDetailView(
                    row: item.archiveRow,
                    baseline: item.baseline,
                    timelineRows: archiveRows
                )
            } label: {
                SnapshotRow(
                    archiveRow: item.archiveRow,
                    showsDeltaSummary: item.showsDeltaSummary,
                    isSelectedBaseline: viewModel.selectedBaselineObservationID == item.archiveRow.observationID
                )
            }
            .swipeActions(edge: .leading) {
                Button {
                    viewModel.toggleBaseline(item.archiveRow)
                    viewModel.comparisonMode = .selected
                } label: {
                    Label(
                        viewModel.selectedBaselineObservationID == item.archiveRow.observationID ? "Unset Baseline" : "Set as Baseline",
                        systemImage: viewModel.selectedBaselineObservationID == item.archiveRow.observationID ? "pin.slash" : "pin"
                    )
                }
                .tint(.indigo)
            }
        }
        .refreshable {
            await viewModel.loadArchiveRows()
        }
    }

    @ToolbarContentBuilder
    private var toolbarContent: some ToolbarContent {
        ToolbarItem(placement: .navigationBarTrailing) {
            Menu {
                Picker("Compare Against", selection: $viewModel.comparisonMode) {
                    Text("Previous").tag(ComparisonMode.previous)
                    ForEach(ComparisonMode.relativeOptions, id: \.interval) { opt in
                        Text(opt.label).tag(ComparisonMode.relativeTime(opt.interval))
                    }
                    if viewModel.selectedBaselineObservationID != nil {
                        Text("Selected Baseline").tag(ComparisonMode.selected)
                    }
                }
            } label: {
                Label(viewModel.comparisonMode.label, systemImage: "arrow.left.arrow.right")
                    .labelStyle(.titleAndIcon)
            }
        }
    }
}

private struct SnapshotListItem: Identifiable {
    let archiveRow: CachedArchiveObservationRow
    let baseline: CachedArchiveObservationRow?
    let showsDeltaSummary: Bool

    var id: Int64 {
        archiveRow.observationID
    }
}

private struct SnapshotRow: View {
    let archiveRow: CachedArchiveObservationRow
    let showsDeltaSummary: Bool
    let isSelectedBaseline: Bool

    private static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .short
        return formatter
    }()

    private var metricCountLabel: String {
        archiveRow.trackedTypeCount == 1
            ? "1 metric"
            : "\(archiveRow.trackedTypeCount) metrics"
    }

    private var recordCountLabel: String {
        archiveRow.visibleRecordCount == 1
            ? "1 record"
            : "\(archiveRow.visibleRecordCount) records"
    }

    private var deltaSummaryText: String {
        let appeared = archiveRow.appearedCount
        let disappeared = archiveRow.disappearedCount
        let changed = archiveRow.representationChangedCount
        let total = appeared + disappeared + changed
        guard total > 0 else { return "No record changes" }

        var parts: [String] = []
        if appeared > 0 { parts.append("\(appeared) new") }
        if disappeared > 0 { parts.append("\(disappeared) missing") }
        if changed > 0 { parts.append("\(changed) changed") }
        return parts.joined(separator: " • ")
    }

    private var deltaSummaryColor: Color {
        if archiveRow.disappearedCount > 0 { return Color.criticalRed }
        if archiveRow.appearedCount + archiveRow.representationChangedCount > 0 { return Color.warningAmber }
        return Color.healthyGreen
    }

    private var deltaSummaryIconName: String {
        let hasChanges = archiveRow.appearedCount
            + archiveRow.disappearedCount
            + archiveRow.representationChangedCount > 0
        return hasChanges ? "arrow.triangle.2.circlepath" : "checkmark.circle"
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack {
                Text(Self.dateFormatter.string(from: archiveRow.observedAt))
                    .font(.subheadline.weight(.semibold))
                Spacer()
                if isSelectedBaseline {
                    Image(systemName: "pin.fill")
                        .foregroundStyle(.indigo)
                        .font(.caption)
                        .accessibilityLabel("Selected as comparison baseline")
                }
            }

            HStack(spacing: 6) {
                Circle()
                    .fill(Color.neutralGray)
                    .frame(width: 8, height: 8)
                Text("Local archive")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Label(metricCountLabel, systemImage: "list.bullet.rectangle")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Label(recordCountLabel, systemImage: "doc.text.magnifyingglass")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Label("Archive observation \(archiveRow.observationID)", systemImage: "externaldrive")
                .font(.caption)
                .foregroundStyle(.secondary)

            if showsDeltaSummary {
                HStack(spacing: 4) {
                    Image(systemName: deltaSummaryIconName)
                    Text(deltaSummaryText)
                }
                .font(.caption)
                .foregroundStyle(deltaSummaryColor)
            }
        }
        .padding(.vertical, 2)
        .accessibilityElement(children: .combine)
    }
}

#Preview {
    SnapshotsView()
        .environment(AppSettings())
}
