import Foundation
import NucleicProtocol

/// A device the user has paired (SYNC §4.2). The host pins `staticPublicKey` at pairing and
/// checks it on every reconnect; revoking a device removes the row so its next handshake
/// fails `.unauthorized`.
public struct PairedDevice: Sendable, Codable, Equatable {
    public let deviceID: String
    public var label: String
    public var staticPublicKey: Data
    public var scope: DeviceScope
    public var pushToken: String?
    public var pairedAt: Date
    public var lastSeenAt: Date?

    public init(
        deviceID: String, label: String, staticPublicKey: Data,
        scope: DeviceScope = .approve, pushToken: String? = nil,
        pairedAt: Date, lastSeenAt: Date? = nil
    ) {
        self.deviceID = deviceID
        self.label = label
        self.staticPublicKey = staticPublicKey
        self.scope = scope
        self.pushToken = pushToken
        self.pairedAt = pairedAt
        self.lastSeenAt = lastSeenAt
    }
}

public protocol PairedDeviceStore: Sendable {
    func device(_ id: String) async -> PairedDevice?
    func all() async -> [PairedDevice]
    func upsert(_ device: PairedDevice) async
    func remove(_ id: String) async
}

/// Default store. The app can persist these (GRDB) later; held in memory for now so pairing
/// works without a schema migration, and so tests are hermetic.
public actor InMemoryPairedDeviceStore: PairedDeviceStore {
    private var devices: [String: PairedDevice] = [:]

    public init(seed: [PairedDevice] = []) {
        for d in seed { devices[d.deviceID] = d }
    }

    public func device(_ id: String) async -> PairedDevice? { devices[id] }
    public func all() async -> [PairedDevice] { Array(devices.values) }
    public func upsert(_ device: PairedDevice) async { devices[device.deviceID] = device }
    public func remove(_ id: String) async { devices[id] = nil }
}
