import Foundation

/// Account-level user settings that are the same on every device and kept in step across the
/// mesh — the first (and, today, only) synced-preferences payload. Distinct from the many
/// per-device `@AppStorage` toggles (theme, transcript detail) that are deliberately local:
/// these describe how the *account* behaves, so a change on the Mac must reflect on the iPhone
/// and vice-versa.
///
/// The host is the source of truth. It stamps the current value into `Welcome.settings` on
/// connect and broadcasts `HostMsg.settings` on every change; a device asks for a change with
/// `ClientMsg.updateSettings`, which the host applies, persists, enforces, and re-broadcasts.
/// Both sides gate the traffic on `WireCapabilities.canSyncSettings` (an older host neither
/// stamps the field nor understands the verb).
///
/// Forward-compatible: every field decodes-if-present so adding one never breaks an older peer.
public struct SyncedSettings: Sendable, Codable, Equatable {
    /// Whether an approval resolved from a remote lock-screen surface — the iOS Live Activity's
    /// inline Allow/Deny — is delivered to the Mac over the Nucleic Edge relay rather than only
    /// the local network. **Off by default**: the path uses Nucleic cloud services, which some
    /// users prefer to avoid, so it is strictly opt-in.
    ///
    /// When on, the host forces the **Covalence** transport on and keeps it locked
    /// (the relayed action can't reach a Mac that isn't in the relay room), and the phone routes
    /// Live-Activity-originated approvals relay-first — the local network is unreliable for a
    /// backgrounded/locked App Intent. When off, the inline buttons deep-link into the app to
    /// resolve locally instead of sending over the cloud.
    public var resolveApprovalsViaCloud: Bool

    public init(resolveApprovalsViaCloud: Bool = false) {
        self.resolveApprovalsViaCloud = resolveApprovalsViaCloud
    }

    /// The resting default (feature off) — used before a host has sent one, and as the decode
    /// fallback for a peer that predates a field.
    public static let `default` = SyncedSettings()

    /// The canonical `UserDefaults` key the host persists this under (and the macOS Settings
    /// toggle binds to), so the store and the UI can never drift apart.
    public static let resolveApprovalsViaCloudKey = "nucleic.resolveApprovalsViaCloud"

    /// The locally-cached `resolveApprovalsViaCloud` flag, readable without a live host. Both the
    /// host and the phone mirror the current value into this key, so a cold background App Intent
    /// (which never mounts the sync store) can decide whether to route a Live-Activity approval
    /// relay-first without waiting for a connection.
    public static func resolveApprovalsViaCloud(from defaults: UserDefaults = .standard) -> Bool {
        defaults.bool(forKey: resolveApprovalsViaCloudKey)
    }

    private enum CodingKeys: String, CodingKey {
        case resolveApprovalsViaCloud
    }

    public init(from decoder: Decoder) throws {
        let c = try decoder.container(keyedBy: CodingKeys.self)
        self.resolveApprovalsViaCloud =
            try c.decodeIfPresent(Bool.self, forKey: .resolveApprovalsViaCloud) ?? false
    }
}
