import Foundation

/// T-iOS-23 · Persistence seam for `SessionCore.UnreadLedger` watermarks.
/// The ledger itself is persistence-agnostic (plan §7) — the App layer wires
/// UserDefaults here. NON-SECRET UI state only (plan §5.3 split: Keychain =
/// secrets, UserDefaults = prefs), same tier as `LastSessionStore`.
protocol UnreadWatermarkStore: Sendable {
    func load() -> [UUID: Int]
    func save(_ watermarks: [UUID: Int])
}

/// UserDefaults-backed implementation with an injectable suite for tests
/// (mirrors `UserDefaultsLastSessionStore`). `@unchecked Sendable`:
/// `UserDefaults` is documented thread-safe and this wrapper adds no mutable
/// state of its own.
struct UserDefaultsUnreadWatermarkStore: UnreadWatermarkStore, @unchecked Sendable {
    private static let key = "unreadWatermarks"

    private let defaults: UserDefaults

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults
    }

    func load() -> [UUID: Int] {
        guard let raw = defaults.dictionary(forKey: Self.key) as? [String: Int] else {
            return [:]
        }
        // Stored data crosses a storage boundary — validate every key; garbage
        // is dropped, never trusted (two case-variant spellings of one UUID
        // collapse via max, so this can never crash on duplicates).
        let pairs = raw.compactMap { key, value in
            UUID(uuidString: key).map { ($0, value) }
        }
        return Dictionary(pairs, uniquingKeysWith: max)
    }

    func save(_ watermarks: [UUID: Int]) {
        let plist = Dictionary(
            uniqueKeysWithValues: watermarks.map { ($0.key.uuidString, $0.value) }
        )
        defaults.set(plist, forKey: Self.key)
    }
}
