import Foundation import SharedKit import WatchConnectivity @MainActor final class WatchConnectivityService: NSObject, WCSessionDelegate { static let shared = WatchConnectivityService() private let store: WatchProfileStore private var handlers: [String: WatchDataHandling] = [:] private override init() { self.store = .shared super.init() registerDefaultHandlers() activateIfSupported() loadCurrentContext() } private func registerDefaultHandlers() { let profileHandler = UserProfileWatchHandler(store: store) registerHandler(profileHandler) let syncableSettingHandler = SyncableSettingWatchHandler(store: store) registerHandler(syncableSettingHandler) } func registerHandler(_ handler: WatchDataHandling) { handlers[handler.key] = handler } private func activateIfSupported() { guard WCSession.isSupported() else { store.setStatus("WatchConnectivity not supported") return } let session = WCSession.default session.delegate = self session.activate() } private func loadCurrentContext() { guard WCSession.isSupported() else { return } let context = WCSession.default.applicationContext let keys = context.keys.sorted().joined(separator: ", ") Logger.debug("Watch loaded current context keys: [\(keys)]") handleContext(context) } private func handleContext(_ context: [String: Any]) { let keys = context.keys.sorted().joined(separator: ", ") Logger.debug("Watch handling context keys: [\(keys)]") for (key, handler) in handlers { guard let data = context[key] as? Data else { continue } handler.handle(data: data) } } func session( _ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error? ) { if let error { Logger.error("Watch WCSession activation failed", error: error) } else { Logger.debug("Watch WCSession activated with state: \(activationState.rawValue)") } updateReachability(using: session) loadCurrentContext() requestSyncIfNeeded() } func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) { Logger.debug("Watch received application context with \(applicationContext.count) keys") handleContext(applicationContext) } func sessionReachabilityDidChange(_ session: WCSession) { Logger.debug("Watch reachability changed: reachable=\(session.isReachable)") updateReachability(using: session) requestSyncIfNeeded() } private func updateReachability(using session: WCSession) { store.setPhoneReachable(session.isReachable) } private func requestSyncIfNeeded() { guard WCSession.isSupported() else { return } let session = WCSession.default if session.isReachable { store.setPhoneReachable(true) store.setStatus("Requesting sync from iPhone...") session.sendMessage([WatchSyncMessageKeys.requestSync: true]) { reply in Logger.debug("Watch received sync reply with \(reply.count) keys") self.handleContext(reply) } errorHandler: { error in Logger.error("Watch sync request failed", error: error) } Logger.debug("Watch requested sync from iPhone (reachable)") } else { store.setPhoneReachable(false) store.setStatus("Open the iPhone app to sync.") session.transferUserInfo([WatchSyncMessageKeys.requestSync: true]) Logger.debug("Watch queued sync request for iPhone launch") } } }