import Foundation

// MARK: - HandshakeState

enum HandshakeState: Int {
    case completed = 0
    case needDeviceVerification = 1
}

// MARK: - HandshakeDevice

struct HandshakeDevice {
    var deviceId: String = ""
    var deviceName: String = ""
    var deviceOs: String = ""
}

// MARK: - PacketHandshake (0x00)

struct PacketHandshake: Packet {
    static let packetId = 0x00

    var privateKey: String = ""       // SHA256(privateKey + "rosetta")
    var publicKey: String = ""        // Compressed secp256k1 public key (hex)
    var protocolVersion: Int = 1
    var heartbeatInterval: Int = 15
    var device = HandshakeDevice()
    var handshakeState: HandshakeState = .needDeviceVerification
    var isMalformed: Bool = false
    var malformedFingerprint: String = ""

    func write(to stream: Stream) {
        stream.writeString(privateKey)
        stream.writeString(publicKey)
        stream.writeInt8(protocolVersion)
        stream.writeInt8(heartbeatInterval)
        stream.writeString(device.deviceId)
        stream.writeString(device.deviceName)
        stream.writeString(device.deviceOs)
        stream.writeInt8(handshakeState.rawValue)
    }

    mutating func read(from stream: Stream) {
        do {
            let parsedPrivateKey = try stream.readStringStrict()
            let parsedPublicKey = try stream.readStringStrict()
            let parsedProtocolVersion = try stream.readInt8Strict()
            let parsedHeartbeatInterval = try stream.readInt8Strict()
            let parsedDeviceId = try stream.readStringStrict()
            let parsedDeviceName = try stream.readStringStrict()
            let parsedDeviceOs = try stream.readStringStrict()
            let rawState = try stream.readInt8Strict()

            guard let parsedState = HandshakeState(rawValue: rawState) else {
                markMalformed("invalid_state:\(rawState)")
                return
            }

            guard !stream.hasRemainingBits() else {
                markMalformed("trailing_bits:\(stream.remainingBits())")
                return
            }

            privateKey = parsedPrivateKey
            publicKey = parsedPublicKey
            protocolVersion = parsedProtocolVersion
            heartbeatInterval = parsedHeartbeatInterval
            device = HandshakeDevice(
                deviceId: parsedDeviceId,
                deviceName: parsedDeviceName,
                deviceOs: parsedDeviceOs
            )
            handshakeState = parsedState
            isMalformed = false
            malformedFingerprint = ""
        } catch {
            markMalformed(Self.errorFingerprint(error))
        }
    }

    private mutating func markMalformed(_ fingerprint: String) {
        privateKey = ""
        publicKey = ""
        protocolVersion = 1
        heartbeatInterval = 15
        device = HandshakeDevice()
        handshakeState = .needDeviceVerification
        isMalformed = true
        malformedFingerprint = fingerprint
    }

    private static func errorFingerprint(_ error: Error) -> String {
        switch error {
        case PacketBitStreamError.underflow(let operation, let neededBits, let remainingBits):
            return "underflow:\(operation):\(neededBits):\(remainingBits)"
        case PacketBitStreamError.invalidStringLength(let length):
            return "invalid_string_length:\(length)"
        default:
            return "parse_error"
        }
    }
}
