import Foundation

private struct StoredPushRelayRegistrationState: Codable {
    var relayHandle: String
    var sendGrant: String
    var relayOrigin: String?
    var gatewayDeviceId: String
    var relayHandleExpiresAtMs: Int64?
    var tokenDebugSuffix: String?
    var lastAPNsTokenHashHex: String
    var installationId: String
    var lastTransport: String
}

enum PushRelayRegistrationStore {
    private static let service = "ai.openclaw.pushrelay"
    private static let registrationStateAccount = "registration-state"
    private static let appAttestKeyIDAccount = "app-attest-key-id"
    private static let appAttestedKeyIDAccount = "app-attested-key-id"

    struct RegistrationState: Codable {
        var relayHandle: String
        var sendGrant: String
        var relayOrigin: String?
        var gatewayDeviceId: String
        var relayHandleExpiresAtMs: Int64?
        var tokenDebugSuffix: String?
        var lastAPNsTokenHashHex: String
        var installationId: String
        var lastTransport: String
    }

    static func loadRegistrationState() -> RegistrationState? {
        guard let raw = KeychainStore.loadString(
            service: self.service,
            account: self.registrationStateAccount),
            let data = raw.data(using: .utf8),
            let decoded = try? JSONDecoder().decode(StoredPushRelayRegistrationState.self, from: data)
        else {
            return nil
        }
        return RegistrationState(
            relayHandle: decoded.relayHandle,
            sendGrant: decoded.sendGrant,
            relayOrigin: decoded.relayOrigin,
            gatewayDeviceId: decoded.gatewayDeviceId,
            relayHandleExpiresAtMs: decoded.relayHandleExpiresAtMs,
            tokenDebugSuffix: decoded.tokenDebugSuffix,
            lastAPNsTokenHashHex: decoded.lastAPNsTokenHashHex,
            installationId: decoded.installationId,
            lastTransport: decoded.lastTransport)
    }

    @discardableResult
    static func saveRegistrationState(_ state: RegistrationState) -> Bool {
        let stored = StoredPushRelayRegistrationState(
            relayHandle: state.relayHandle,
            sendGrant: state.sendGrant,
            relayOrigin: state.relayOrigin,
            gatewayDeviceId: state.gatewayDeviceId,
            relayHandleExpiresAtMs: state.relayHandleExpiresAtMs,
            tokenDebugSuffix: state.tokenDebugSuffix,
            lastAPNsTokenHashHex: state.lastAPNsTokenHashHex,
            installationId: state.installationId,
            lastTransport: state.lastTransport)
        guard let data = try? JSONEncoder().encode(stored),
              let raw = String(data: data, encoding: .utf8)
        else {
            return false
        }
        return KeychainStore.saveString(raw, service: self.service, account: self.registrationStateAccount)
    }

    @discardableResult
    static func clearRegistrationState() -> Bool {
        KeychainStore.delete(service: self.service, account: self.registrationStateAccount)
    }

    static func loadAppAttestKeyID() -> String? {
        let value = KeychainStore.loadString(service: self.service, account: self.appAttestKeyIDAccount)?
            .trimmingCharacters(in: .whitespacesAndNewlines)
        if value?.isEmpty == false { return value }
        return nil
    }

    @discardableResult
    static func saveAppAttestKeyID(_ keyID: String) -> Bool {
        KeychainStore.saveString(keyID, service: self.service, account: self.appAttestKeyIDAccount)
    }

    @discardableResult
    static func clearAppAttestKeyID() -> Bool {
        KeychainStore.delete(service: self.service, account: self.appAttestKeyIDAccount)
    }

    static func loadAttestedKeyID() -> String? {
        let value = KeychainStore.loadString(service: self.service, account: self.appAttestedKeyIDAccount)?
            .trimmingCharacters(in: .whitespacesAndNewlines)
        if value?.isEmpty == false { return value }
        return nil
    }

    @discardableResult
    static func saveAttestedKeyID(_ keyID: String) -> Bool {
        KeychainStore.saveString(keyID, service: self.service, account: self.appAttestedKeyIDAccount)
    }

    @discardableResult
    static func clearAttestedKeyID() -> Bool {
        KeychainStore.delete(service: self.service, account: self.appAttestedKeyIDAccount)
    }
}
