//
// WorkoutSummaryView.swift
// Workouts
//
// Copyright 2025 Rouslan Zenetl. All Rights Reserved.
//

import SwiftUI
import SwiftData

/// Post-workout summary shown right after a workout finishes. Queried by id so the
/// health metrics (calories, heart rate) fill in live as they arrive from the watch
/// over the WatchConnectivity bridge.
struct WorkoutSummaryView: View {
    @Environment(\.dismiss) private var dismiss
    @Query private var workouts: [Workout]
    let onDone: () -> Void

    init(workoutID: String, onDone: @escaping () -> Void) {
        self.onDone = onDone
        _workouts = Query(filter: #Predicate<Workout> { $0.id == workoutID })
    }

    private var workout: Workout? { workouts.first }

    var body: some View {
        NavigationStack {
            Group {
                // The fromLive guard also covers the query vending a workout whose
                // cache row was deleted within the same view-graph update (remote
                // delete / reconcile prune) — reading a dead @Model traps.
                if let workout, let doc = WorkoutDocument(fromLive: workout) {
                    ScrollView {
                        VStack(spacing: 20) {
                            Image(systemName: "checkmark.seal.fill")
                                .font(.system(size: 48))
                                .foregroundStyle(.green)
                                .padding(.top, 8)
                            Text(doc.routineName ?? Routine.unnamed)
                                .font(.title2.bold())

                            WorkoutMetricsView(workout: workout)

                            if doc.metrics == nil {
                                Label("Saving to Apple Health…", systemImage: "heart.text.square")
                                    .font(.footnote)
                                    .foregroundStyle(.secondary)
                            }
                        }
                        .padding()
                    }
                } else {
                    // The workout was removed (e.g. discarded) — nothing to summarize.
                    ContentUnavailableView("Workout Ended", systemImage: "checkmark.circle")
                }
            }
            .navigationTitle("Summary")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") { onDone() }
                }
            }
        }
    }
}

// MARK: - Metric tiles (shared by the summary sheet and the per-workout detail)

/// Renders the available health/strength metrics for a finished workout as a tile
/// grid plus an optional heart-rate-zone bar. Reused by `WorkoutSummaryView` and the
/// completed-workout detail section.
struct WorkoutMetricsView: View {
    let workout: Workout
    @AppStorage("weightUnit") private var weightUnit: WeightUnit = .lb

    // Every read goes through this liveness-guarded snapshot: the cache row can be
    // deleted out from under a retained `Workout` (remote delete, reconcile prune)
    // while a parent re-evaluates mid-transition, and reading a persisted property
    // on a dead @Model traps — see `WorkoutDocument.init?(fromLive:)`.
    private var doc: WorkoutDocument? { WorkoutDocument(fromLive: workout) }

    private var metrics: WorkoutMetrics? { doc?.metrics }

    private var durationSeconds: Int? {
        guard let doc, let end = doc.end else { return nil }
        return max(0, Int(end.timeIntervalSince(doc.start)))
    }

    private var volume: Double {
        metrics?.totalVolume ?? WorkoutVolume.total(doc?.logs ?? [])
    }

    var body: some View {
        VStack(spacing: 16) {
            LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 12) {
                if let durationSeconds {
                    MetricTile(icon: "clock.fill", tint: .blue, value: durationText(durationSeconds), label: "Duration")
                }
                if let kcal = metrics?.activeEnergyKcal {
                    MetricTile(icon: "flame.fill", tint: .orange, value: "\(Int(kcal.rounded()))", label: "Active cal")
                }
                if let avg = metrics?.avgHeartRate {
                    MetricTile(icon: "heart.fill", tint: .red, value: "\(Int(avg.rounded()))", label: "Avg BPM")
                }
                if let max = metrics?.maxHeartRate {
                    MetricTile(icon: "bolt.heart.fill", tint: .pink, value: "\(Int(max.rounded()))", label: "Max BPM")
                }
                if volume > 0 {
                    MetricTile(icon: "scalemass.fill", tint: .purple, value: volumeText, label: "Volume")
                }
            }

            if let zones = metrics?.hrZoneSeconds, zones.contains(where: { $0 > 0 }) {
                HRZoneBar(zoneSeconds: zones)
            }

            if metrics?.source == .phoneEstimate {
                Text("Calories estimated — wear your Apple Watch for measured stats.")
                    .font(.caption2)
                    .foregroundStyle(.secondary)
                    .multilineTextAlignment(.center)
            }
        }
    }

    private var volumeText: String {
        "\(Int(volume.rounded())) \(weightUnit.abbreviation)"
    }

    private func durationText(_ seconds: Int) -> String {
        let minutes = seconds / 60
        if minutes >= 60 { return "\(minutes / 60)h \(minutes % 60)m" }
        return "\(minutes)m \(seconds % 60)s"
    }
}

struct MetricTile: View {
    let icon: String
    let tint: Color
    let value: String
    let label: String

    var body: some View {
        VStack(spacing: 4) {
            Image(systemName: icon)
                .font(.title2)
                .foregroundStyle(tint)
            Text(value)
                .font(.title3.bold())
                .monospacedDigit()
            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 10)
        .background(.quaternary.opacity(0.4), in: RoundedRectangle(cornerRadius: 12))
    }
}

/// Proportional stacked bar of time spent in each of the 5 heart-rate zones (low→high),
/// with a numbered legend so the zones read without relying on color, and a single
/// spoken summary of time per zone for VoiceOver.
struct HRZoneBar: View {
    let zoneSeconds: [Double]

    private let colors: [Color] = [.blue, .green, .yellow, .orange, .red]

    /// Indices of the zones that actually accrued time — the only ones drawn and listed.
    private var activeZones: [Int] {
        (0..<min(zoneSeconds.count, colors.count)).filter { zoneSeconds[$0] > 0 }
    }

    var body: some View {
        let total = max(zoneSeconds.reduce(0, +), 1)
        VStack(alignment: .leading, spacing: 8) {
            Text("Heart Rate Zones")
                .font(.caption)
                .foregroundStyle(.secondary)
            GeometryReader { geo in
                HStack(spacing: 2) {
                    ForEach(activeZones, id: \.self) { zone in
                        colors[zone]
                            .frame(width: max(2, geo.size.width * (zoneSeconds[zone] / total)))
                    }
                }
            }
            .frame(height: 12)
            .clipShape(Capsule())

            // Numbered legend — each active zone's swatch beside its number, so the
            // split reads for color-blind (and all) sighted users, not by hue alone.
            HStack(spacing: 12) {
                ForEach(activeZones, id: \.self) { zone in
                    HStack(spacing: 4) {
                        RoundedRectangle(cornerRadius: 3)
                            .fill(colors[zone])
                            .frame(width: 10, height: 10)
                        Text("Zone \(zone + 1)")
                            .font(.caption2)
                            .foregroundStyle(.secondary)
                    }
                }
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        // Collapse the whole bar+legend into one element with a spoken per-zone breakdown.
        .accessibilityElement(children: .ignore)
        .accessibilityLabel("Heart rate zones")
        .accessibilityValue(spokenSummary)
    }

    /// "Zone 1, 2 min 30 sec. Zone 2, 5 min." — time in each zone that saw activity.
    private var spokenSummary: String {
        activeZones
            .map { "Zone \($0 + 1), \(spokenDuration(Int(zoneSeconds[$0].rounded())))" }
            .joined(separator: ". ")
    }

    private func spokenDuration(_ seconds: Int) -> String {
        let m = seconds / 60, s = seconds % 60
        if m > 0 && s > 0 { return "\(m) min \(s) sec" }
        if m > 0 { return "\(m) min" }
        return "\(s) sec"
    }
}
