// Generated by scripts/protocol-gen-swift.ts — do not edit by hand
import Foundation

public let GATEWAY_PROTOCOL_VERSION = 1

public enum ErrorCode: String, Codable {
    case notLinked = "NOT_LINKED"
    case agentTimeout = "AGENT_TIMEOUT"
    case invalidRequest = "INVALID_REQUEST"
    case unavailable = "UNAVAILABLE"
}

public struct Hello: Codable {
    public let type: String
    public let minprotocol: Int
    public let maxprotocol: Int
    public let client: [String: AnyCodable]
    public let caps: [String]?
    public let auth: [String: AnyCodable]?
    public let locale: String?
    public let useragent: String?

    public init(
        type: String,
        minprotocol: Int,
        maxprotocol: Int,
        client: [String: AnyCodable],
        caps: [String]?,
        auth: [String: AnyCodable]?,
        locale: String?,
        useragent: String?
    ) {
        self.type = type
        self.minprotocol = minprotocol
        self.maxprotocol = maxprotocol
        self.client = client
        self.caps = caps
        self.auth = auth
        self.locale = locale
        self.useragent = useragent
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case minprotocol = "minProtocol"
        case maxprotocol = "maxProtocol"
        case client
        case caps
        case auth
        case locale
        case useragent = "userAgent"
    }
}

public struct HelloOk: Codable {
    public let type: String
    public let _protocol: Int
    public let server: [String: AnyCodable]
    public let features: [String: AnyCodable]
    public let snapshot: Snapshot
    public let policy: [String: AnyCodable]

    public init(
        type: String,
        _protocol: Int,
        server: [String: AnyCodable],
        features: [String: AnyCodable],
        snapshot: Snapshot,
        policy: [String: AnyCodable]
    ) {
        self.type = type
        self._protocol = _protocol
        self.server = server
        self.features = features
        self.snapshot = snapshot
        self.policy = policy
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case _protocol = "protocol"
        case server
        case features
        case snapshot
        case policy
    }
}

public struct HelloError: Codable {
    public let type: String
    public let reason: String
    public let expectedprotocol: Int?
    public let minclient: String?

    public init(
        type: String,
        reason: String,
        expectedprotocol: Int?,
        minclient: String?
    ) {
        self.type = type
        self.reason = reason
        self.expectedprotocol = expectedprotocol
        self.minclient = minclient
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case reason
        case expectedprotocol = "expectedProtocol"
        case minclient = "minClient"
    }
}

public struct RequestFrame: Codable {
    public let type: String
    public let id: String
    public let method: String
    public let params: AnyCodable?

    public init(
        type: String,
        id: String,
        method: String,
        params: AnyCodable?
    ) {
        self.type = type
        self.id = id
        self.method = method
        self.params = params
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case id
        case method
        case params
    }
}

public struct ResponseFrame: Codable {
    public let type: String
    public let id: String
    public let ok: Bool
    public let payload: AnyCodable?
    public let error: [String: AnyCodable]?

    public init(
        type: String,
        id: String,
        ok: Bool,
        payload: AnyCodable?,
        error: [String: AnyCodable]?
    ) {
        self.type = type
        self.id = id
        self.ok = ok
        self.payload = payload
        self.error = error
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case id
        case ok
        case payload
        case error
    }
}

public struct EventFrame: Codable {
    public let type: String
    public let event: String
    public let payload: AnyCodable?
    public let seq: Int?
    public let stateversion: [String: AnyCodable]?

    public init(
        type: String,
        event: String,
        payload: AnyCodable?,
        seq: Int?,
        stateversion: [String: AnyCodable]?
    ) {
        self.type = type
        self.event = event
        self.payload = payload
        self.seq = seq
        self.stateversion = stateversion
    }
    private enum CodingKeys: String, CodingKey {
        case type
        case event
        case payload
        case seq
        case stateversion = "stateVersion"
    }
}

public struct PresenceEntry: Codable {
    public let host: String?
    public let ip: String?
    public let version: String?
    public let mode: String?
    public let lastinputseconds: Int?
    public let reason: String?
    public let tags: [String]?
    public let text: String?
    public let ts: Int
    public let instanceid: String?

    public init(
        host: String?,
        ip: String?,
        version: String?,
        mode: String?,
        lastinputseconds: Int?,
        reason: String?,
        tags: [String]?,
        text: String?,
        ts: Int,
        instanceid: String?
    ) {
        self.host = host
        self.ip = ip
        self.version = version
        self.mode = mode
        self.lastinputseconds = lastinputseconds
        self.reason = reason
        self.tags = tags
        self.text = text
        self.ts = ts
        self.instanceid = instanceid
    }
    private enum CodingKeys: String, CodingKey {
        case host
        case ip
        case version
        case mode
        case lastinputseconds = "lastInputSeconds"
        case reason
        case tags
        case text
        case ts
        case instanceid = "instanceId"
    }
}

public struct StateVersion: Codable {
    public let presence: Int
    public let health: Int

    public init(
        presence: Int,
        health: Int
    ) {
        self.presence = presence
        self.health = health
    }
    private enum CodingKeys: String, CodingKey {
        case presence
        case health
    }
}

public struct Snapshot: Codable {
    public let presence: [PresenceEntry]
    public let health: AnyCodable
    public let stateversion: StateVersion
    public let uptimems: Int

    public init(
        presence: [PresenceEntry],
        health: AnyCodable,
        stateversion: StateVersion,
        uptimems: Int
    ) {
        self.presence = presence
        self.health = health
        self.stateversion = stateversion
        self.uptimems = uptimems
    }
    private enum CodingKeys: String, CodingKey {
        case presence
        case health
        case stateversion = "stateVersion"
        case uptimems = "uptimeMs"
    }
}

public struct ErrorShape: Codable {
    public let code: String
    public let message: String
    public let details: AnyCodable?
    public let retryable: Bool?
    public let retryafterms: Int?

    public init(
        code: String,
        message: String,
        details: AnyCodable?,
        retryable: Bool?,
        retryafterms: Int?
    ) {
        self.code = code
        self.message = message
        self.details = details
        self.retryable = retryable
        self.retryafterms = retryafterms
    }
    private enum CodingKeys: String, CodingKey {
        case code
        case message
        case details
        case retryable
        case retryafterms = "retryAfterMs"
    }
}

public struct AgentEvent: Codable {
    public let runid: String
    public let seq: Int
    public let stream: String
    public let ts: Int
    public let data: [String: AnyCodable]

    public init(
        runid: String,
        seq: Int,
        stream: String,
        ts: Int,
        data: [String: AnyCodable]
    ) {
        self.runid = runid
        self.seq = seq
        self.stream = stream
        self.ts = ts
        self.data = data
    }
    private enum CodingKeys: String, CodingKey {
        case runid = "runId"
        case seq
        case stream
        case ts
        case data
    }
}

public struct SendParams: Codable {
    public let to: String
    public let message: String
    public let mediaurl: String?
    public let provider: String?
    public let idempotencykey: String

    public init(
        to: String,
        message: String,
        mediaurl: String?,
        provider: String?,
        idempotencykey: String
    ) {
        self.to = to
        self.message = message
        self.mediaurl = mediaurl
        self.provider = provider
        self.idempotencykey = idempotencykey
    }
    private enum CodingKeys: String, CodingKey {
        case to
        case message
        case mediaurl = "mediaUrl"
        case provider
        case idempotencykey = "idempotencyKey"
    }
}

public struct AgentParams: Codable {
    public let message: String
    public let to: String?
    public let sessionid: String?
    public let thinking: String?
    public let deliver: Bool?
    public let timeout: Int?
    public let idempotencykey: String

    public init(
        message: String,
        to: String?,
        sessionid: String?,
        thinking: String?,
        deliver: Bool?,
        timeout: Int?,
        idempotencykey: String
    ) {
        self.message = message
        self.to = to
        self.sessionid = sessionid
        self.thinking = thinking
        self.deliver = deliver
        self.timeout = timeout
        self.idempotencykey = idempotencykey
    }
    private enum CodingKeys: String, CodingKey {
        case message
        case to
        case sessionid = "sessionId"
        case thinking
        case deliver
        case timeout
        case idempotencykey = "idempotencyKey"
    }
}

public struct TickEvent: Codable {
    public let ts: Int

    public init(
        ts: Int
    ) {
        self.ts = ts
    }
    private enum CodingKeys: String, CodingKey {
        case ts
    }
}

public struct ShutdownEvent: Codable {
    public let reason: String
    public let restartexpectedms: Int?

    public init(
        reason: String,
        restartexpectedms: Int?
    ) {
        self.reason = reason
        self.restartexpectedms = restartexpectedms
    }
    private enum CodingKeys: String, CodingKey {
        case reason
        case restartexpectedms = "restartExpectedMs"
    }
}

public enum GatewayFrame: Codable {
    case hello(Hello)
    case helloOk(HelloOk)
    case helloError(HelloError)
    case req(RequestFrame)
    case res(ResponseFrame)
    case event(EventFrame)
    case unknown(type: String, raw: [String: AnyCodable])

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let raw = try container.decode([String: AnyCodable].self)
        guard let type = raw["type"]?.value as? String else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "missing type")
        }
        switch type {
        case "hello":
            self = .hello(try Self.decodePayload(Hello.self, from: raw))
        case "hello-ok":
            self = .helloOk(try Self.decodePayload(HelloOk.self, from: raw))
        case "hello-error":
            self = .helloError(try Self.decodePayload(HelloError.self, from: raw))
        case "req":
            self = .req(try Self.decodePayload(RequestFrame.self, from: raw))
        case "res":
            self = .res(try Self.decodePayload(ResponseFrame.self, from: raw))
        case "event":
            self = .event(try Self.decodePayload(EventFrame.self, from: raw))
        default:
            self = .unknown(type: type, raw: raw)
        }
    }

    public func encode(to encoder: Encoder) throws {
        switch self {
        case .hello(let v): try v.encode(to: encoder)
        case .helloOk(let v): try v.encode(to: encoder)
        case .helloError(let v): try v.encode(to: encoder)
        case .req(let v): try v.encode(to: encoder)
        case .res(let v): try v.encode(to: encoder)
        case .event(let v): try v.encode(to: encoder)
        case .unknown(_, let raw):
            var container = encoder.singleValueContainer()
            try container.encode(raw)
        }
    }


    private static func decodePayload<T: Decodable>(_ type: T.Type, from raw: [String: AnyCodable]) throws -> T {
        let data = try JSONSerialization.data(withJSONObject: raw)
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    }

}
