import Foundation
import SwiftUI

/// Process-wide collector for bundled-resource decode failures.
///
/// The app ships a handful of reference JSON blobs (BTS aggregates, jumpseat
/// rules, crewbases, aircraft equipment catalog, TSA wait baselines). Each
/// loader has a `catch` block that prints the error and falls back to empty
/// data — which means the UI silently shows "no data" when something is
/// actually broken (file missing from the bundle, schema drift, corrupt JSON).
///
/// `DataIntegrityMonitor` is the central place those loaders report into.
/// Failures are surfaced as a dismissible banner in `RootView` so the user
/// at least knows something didn't load instead of being told "no data" with
/// no context.
///
/// Lifetime is process-scoped: clearing the banner just hides it for the
/// remainder of the session; the next launch re-runs all loaders and the
/// banner can re-appear if anything still fails.
@MainActor
final class DataIntegrityMonitor: ObservableObject {

    static let shared = DataIntegrityMonitor()

    /// Human-readable list of bundled-resource decode failures. One entry
    /// per reported failure in the form `"<resource>: <error>"`.
    @Published var failures: [String] = []

    /// Human-readable list of SwiftData save failures. Tracked separately
    /// from decode failures because the user can act on these (their edits
    /// didn't persist) and the visual treatment is different (red banner,
    /// not yellow).
    @Published var saveFailures: [String] = []

    /// True when at least one decode failure has been reported this
    /// session (banner uncleared).
    var hasFailures: Bool { !failures.isEmpty }

    /// True when at least one save failure has been reported this session.
    var hasSaveFailures: Bool { !saveFailures.isEmpty }

    private init() {}

    /// Append a decode failure for `resource` (a basename like
    /// `bts_bundle.json`). Also prints to stdout so the failure shows up
    /// in the Xcode console exactly like the existing per-loader logs.
    func report(_ resource: String, error: Error) {
        let entry = "\(resource): \(error.localizedDescription)"
        failures.append(entry)
        print("[DataIntegrityMonitor] \(entry)")
    }

    /// Append a save failure for `operation` (a short verb like "save flight"
    /// or "delete flight"). The user-facing banner uses these to warn that
    /// their last edit didn't persist.
    func reportSaveFailure(_ operation: String, error: Error) {
        let entry = "\(operation): \(error.localizedDescription)"
        saveFailures.append(entry)
        print("[DataIntegrityMonitor] SAVE FAILED — \(entry)")
    }

    /// Hide the decode-failure banner for the rest of the session. Does
    /// not persist — failures may re-surface on the next launch if loaders
    /// still fail.
    func clear() {
        failures.removeAll()
    }

    /// Clear the save-failure list. Call after a successful retry, or
    /// when the user acknowledges the banner.
    func clearSaveFailures() {
        saveFailures.removeAll()
    }
}
