import Foundation

/// 通过 RTCDataChannel 传输的控制指令。
/// 与 control_message.proto (proto3) 二进制格式完全兼容（手写极简 protobuf 编解码，
/// 免去 SwiftProtobuf 依赖与代码生成）。
/// 坐标 x/y/x1/y1/x2/y2 均为相对屏幕的百分比，取值范围 0.0 ~ 1.0。
struct ControlMessage {

    enum Action: Int {
        case unknown = 0
        case touch = 1
        case swipe = 2
        case key = 3
        case longPress = 4
        case motionEvent = 5
        case setResolution = 6      // 控制端请求被控端切换屏幕采集分辨率
        case reportResolution = 7   // 被控端上报当前实际采集分辨率
        case setStreamMode = 8      // 控制端请求被控端切换屏幕串流模式
        case reportStreamMode = 9   // 被控端上报当前生效的串流模式
    }

    var action: Action = .unknown   // field 1, varint
    var x: Double = 0               // field 2, fixed64
    var y: Double = 0               // field 3, fixed64
    var x1: Double = 0              // field 4, fixed64
    var y1: Double = 0              // field 5, fixed64
    var x2: Double = 0              // field 6, fixed64
    var y2: Double = 0              // field 7, fixed64
    var duration: Int64 = 0         // field 8, varint
    var keyCode: Int32 = 0          // field 9, varint
    var keyAction: Int32 = 0        // field 10, varint (0=按下 1=抬起)
    var motionAction: Int32 = 0     // field 11, varint (0=DOWN 1=UP 2=MOVE 3=CANCEL)
    var width: Int32 = 0            // field 12, varint
    var height: Int32 = 0           // field 13, varint
    var fps: Int32 = 0              // field 14, varint
    var streamMode: Int32 = 0       // field 15, varint (0=WebRTC 1=自编码)
    /// 被控端支持的帧率档位列表（REPORT_RESOLUTION 上报，按屏幕刷新率筛选，升序）。
    var supportedFps: [Int32] = []  // field 16, repeated varint (packed)

    // MARK: - Encode

    func serializedData() -> Data {
        var w = ProtoWriter()
        w.writeVarintField(1, UInt64(action.rawValue))
        w.writeDoubleField(2, x)
        w.writeDoubleField(3, y)
        w.writeDoubleField(4, x1)
        w.writeDoubleField(5, y1)
        w.writeDoubleField(6, x2)
        w.writeDoubleField(7, y2)
        w.writeVarintField(8, UInt64(bitPattern: duration))
        w.writeVarintField(9, UInt64(bitPattern: Int64(keyCode)))
        w.writeVarintField(10, UInt64(bitPattern: Int64(keyAction)))
        w.writeVarintField(11, UInt64(bitPattern: Int64(motionAction)))
        w.writeVarintField(12, UInt64(bitPattern: Int64(width)))
        w.writeVarintField(13, UInt64(bitPattern: Int64(height)))
        w.writeVarintField(14, UInt64(bitPattern: Int64(fps)))
        w.writeVarintField(15, UInt64(bitPattern: Int64(streamMode)))
        // repeated int32 supported_fps = 16（packed 编码）；空列表不编码
        if !supportedFps.isEmpty {
            var payload = ProtoWriter()
            for v in supportedFps {
                payload.writeVarint(UInt64(bitPattern: Int64(v)))
            }
            w.writeVarint(UInt64(16 << 3 | 2))
            w.writeVarint(UInt64(payload.data.count))
            w.data.append(payload.data)
        }
        return w.data
    }

    // MARK: - Decode

    static func parse(from data: Data) -> ControlMessage? {
        var msg = ControlMessage()
        var r = ProtoReader(data: data)
        while let (field, wire) = r.readTag() {
            switch (field, wire) {
            case (1, 0):
                guard let v = r.readVarint() else { return nil }
                msg.action = Action(rawValue: Int(v)) ?? .unknown
            case (2, 1): guard let v = r.readDouble() else { return nil }; msg.x = v
            case (3, 1): guard let v = r.readDouble() else { return nil }; msg.y = v
            case (4, 1): guard let v = r.readDouble() else { return nil }; msg.x1 = v
            case (5, 1): guard let v = r.readDouble() else { return nil }; msg.y1 = v
            case (6, 1): guard let v = r.readDouble() else { return nil }; msg.x2 = v
            case (7, 1): guard let v = r.readDouble() else { return nil }; msg.y2 = v
            case (8, 0): guard let v = r.readVarint() else { return nil }; msg.duration = Int64(bitPattern: v)
            case (9, 0): guard let v = r.readVarint() else { return nil }; msg.keyCode = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (10, 0): guard let v = r.readVarint() else { return nil }; msg.keyAction = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (11, 0): guard let v = r.readVarint() else { return nil }; msg.motionAction = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (12, 0): guard let v = r.readVarint() else { return nil }; msg.width = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (13, 0): guard let v = r.readVarint() else { return nil }; msg.height = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (14, 0): guard let v = r.readVarint() else { return nil }; msg.fps = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (15, 0): guard let v = r.readVarint() else { return nil }; msg.streamMode = Int32(truncatingIfNeeded: Int64(bitPattern: v))
            case (16, 2):
                // packed repeated int32：先读长度，再在区间内逐个读 varint
                guard let len = r.readVarint() else { return nil }
                let end = r.offset + Int(len)
                guard end <= data.endIndex else { return nil }
                while r.offset < end {
                    guard let v = r.readVarint() else { return nil }
                    msg.supportedFps.append(Int32(truncatingIfNeeded: Int64(bitPattern: v)))
                }
            case (16, 0):
                // 兼容非 packed 编码（逐项 varint）
                guard let v = r.readVarint() else { return nil }
                msg.supportedFps.append(Int32(truncatingIfNeeded: Int64(bitPattern: v)))
            default:
                // 未知字段按 wire type 跳过
                if !r.skip(wireType: wire) { return nil }
            }
        }
        return msg
    }
}

// MARK: - 极简 protobuf 读写器

private struct ProtoWriter {
    var data = Data()

    mutating func writeVarint(_ value: UInt64) {
        var v = value
        while v >= 0x80 {
            data.append(UInt8((v & 0x7F) | 0x80))
            v >>= 7
        }
        data.append(UInt8(v))
    }

    /// proto3：默认值(0)不编码
    mutating func writeVarintField(_ field: Int, _ value: UInt64) {
        guard value != 0 else { return }
        writeVarint(UInt64(field << 3 | 0))
        writeVarint(value)
    }

    mutating func writeDoubleField(_ field: Int, _ value: Double) {
        guard value != 0 else { return }
        writeVarint(UInt64(field << 3 | 1))
        var bits = value.bitPattern.littleEndian
        withUnsafeBytes(of: &bits) { data.append(contentsOf: $0) }
    }
}

private struct ProtoReader {
    let data: Data
    var offset: Int

    init(data: Data) {
        self.data = data
        self.offset = data.startIndex
    }

    mutating func readTag() -> (Int, Int)? {
        guard offset < data.endIndex, let key = readVarint() else { return nil }
        return (Int(key >> 3), Int(key & 0x7))
    }

    mutating func readVarint() -> UInt64? {
        var result: UInt64 = 0
        var shift: UInt64 = 0
        while offset < data.endIndex {
            let byte = data[offset]
            offset += 1
            result |= UInt64(byte & 0x7F) << shift
            if byte & 0x80 == 0 { return result }
            shift += 7
            if shift >= 64 { return nil }
        }
        return nil
    }

    mutating func readDouble() -> Double? {
        guard offset + 8 <= data.endIndex else { return nil }
        var bits: UInt64 = 0
        for i in (0..<8).reversed() {
            bits = (bits << 8) | UInt64(data[offset + i])
        }
        offset += 8
        return Double(bitPattern: bits)
    }

    mutating func skip(wireType: Int) -> Bool {
        switch wireType {
        case 0: return readVarint() != nil
        case 1:
            guard offset + 8 <= data.endIndex else { return false }
            offset += 8
            return true
        case 2:
            guard let len = readVarint(), offset + Int(len) <= data.endIndex else { return false }
            offset += Int(len)
            return true
        case 5:
            guard offset + 4 <= data.endIndex else { return false }
            offset += 4
            return true
        default:
            return false
        }
    }
}
