package com.rosetta.messenger.network

/**
 * Binary stream for protocol packets
 * Matches the React Native implementation exactly
 */
class Stream(stream: ByteArray = ByteArray(0)) {
    private var _stream = mutableListOf<Int>()
    private var _readPointer = 0
    private var _writePointer = 0
    
    init {
        _stream = stream.map { it.toInt() and 0xFF }.toMutableList()
    }
    
    fun getStream(): ByteArray {
        return _stream.map { it.toByte() }.toByteArray()
    }

    fun getReadPointerBits(): Int = _readPointer

    fun getTotalBits(): Int = _stream.size * 8

    fun getRemainingBits(): Int = getTotalBits() - _readPointer

    fun hasRemainingBits(): Boolean = _readPointer < getTotalBits()
    
    fun setStream(stream: ByteArray) {
        _stream = stream.map { it.toInt() and 0xFF }.toMutableList()
        _readPointer = 0
    }
    
    fun writeInt8(value: Int) {
        val negationBit = if (value < 0) 1 else 0
        val int8Value = Math.abs(value) and 0xFF
        
        ensureCapacity(_writePointer shr 3)
        _stream[_writePointer shr 3] = _stream[_writePointer shr 3] or (negationBit shl (7 - (_writePointer and 7)))
        _writePointer++
        
        for (i in 0 until 8) {
            val bit = (int8Value shr (7 - i)) and 1
            ensureCapacity(_writePointer shr 3)
            _stream[_writePointer shr 3] = _stream[_writePointer shr 3] or (bit shl (7 - (_writePointer and 7)))
            _writePointer++
        }
    }
    
    fun readInt8(): Int {
        var value = 0
        val negationBit = (_stream[_readPointer shr 3] shr (7 - (_readPointer and 7))) and 1
        _readPointer++
        
        for (i in 0 until 8) {
            val bit = (_stream[_readPointer shr 3] shr (7 - (_readPointer and 7))) and 1
            value = value or (bit shl (7 - i))
            _readPointer++
        }
        
        return if (negationBit == 1) -value else value
    }
    
    fun writeBit(value: Int) {
        val bit = value and 1
        ensureCapacity(_writePointer shr 3)
        _stream[_writePointer shr 3] = _stream[_writePointer shr 3] or (bit shl (7 - (_writePointer and 7)))
        _writePointer++
    }
    
    fun readBit(): Int {
        val bit = (_stream[_readPointer shr 3] shr (7 - (_readPointer and 7))) and 1
        _readPointer++
        return bit
    }
    
    fun writeBoolean(value: Boolean) {
        writeBit(if (value) 1 else 0)
    }
    
    fun readBoolean(): Boolean {
        return readBit() == 1
    }
    
    fun writeInt16(value: Int) {
        writeInt8(value shr 8)
        writeInt8(value and 0xFF)
    }
    
    fun readInt16(): Int {
        val high = readInt8() shl 8
        return high or readInt8()
    }
    
    fun writeInt32(value: Int) {
        writeInt16(value shr 16)
        writeInt16(value and 0xFFFF)
    }
    
    fun readInt32(): Int {
        val high = readInt16() shl 16
        return high or readInt16()
    }
    
    fun writeInt64(value: Long) {
        val high = (value shr 32).toInt()
        val low = (value and 0xFFFFFFFF).toInt()
        writeInt32(high)
        writeInt32(low)
    }
    
    fun readInt64(): Long {
        val high = readInt32().toLong()
        val low = (readInt32().toLong() and 0xFFFFFFFFL)
        return (high shl 32) or low
    }
    
    fun writeString(value: String) {
        writeInt32(value.length)
        for (char in value) {
            writeInt16(char.code)
        }
    }
    
    fun readString(): String {
        val length = readInt32()
        // Desktop parity + safety: don't trust malformed string length.
        val bytesAvailable = _stream.size - (_readPointer shr 3)
        if (length < 0 || (length.toLong() * 2L) > bytesAvailable.toLong()) {
            android.util.Log.w(
                    "RosettaStream",
                    "readString invalid length=$length, bytesAvailable=$bytesAvailable, readPointer=$_readPointer"
            )
            return ""
        }
        val sb = StringBuilder()
        for (i in 0 until length) {
            sb.append(readInt16().toChar())
        }
        return sb.toString()
    }
    
    fun writeBytes(value: ByteArray) {
        writeInt32(value.size)
        for (byte in value) {
            writeInt8(byte.toInt())
        }
    }
    
    fun readBytes(): ByteArray {
        val length = readInt32()
        val bytes = ByteArray(length)
        for (i in 0 until length) {
            bytes[i] = readInt8().toByte()
        }
        return bytes
    }
    
    private fun ensureCapacity(index: Int) {
        while (_stream.size <= index) {
            _stream.add(0)
        }
    }
}
