package com.correx.infrastructure.artifactscas.segment

import org.bouncycastle.crypto.digests.Blake3Digest
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.zip.*

object SegmentLayout {
    const val HASH_SIZE: Int = 32
    const val HEADER_SIZE: Int = 4 + 4 + HASH_SIZE
    private const val BLAKE3_DIGEST_BITS: Int = 256

    fun encodeHeader(payload: ByteArray, hash: ByteArray): ByteArray {
        require(hash.size == HASH_SIZE) { "hash must be $HASH_SIZE bytes" }
        val crc = CRC32C().apply { update(payload, 0, payload.size) }.value.toInt()
        return ByteBuffer.allocate(HEADER_SIZE)
            .order(ByteOrder.BIG_ENDIAN)
            .putInt(payload.size)
            .putInt(crc)
            .put(hash)
            .array()
    }

    fun decodeHeader(header: ByteArray): Triple<Int, Int, ByteArray> {
        require(header.size == HEADER_SIZE) { "header must be $HEADER_SIZE bytes" }
        val buf = ByteBuffer.wrap(header).order(ByteOrder.BIG_ENDIAN)
        val length = buf.int
        val crc = buf.int
        val hash = ByteArray(HASH_SIZE)
        buf.get(hash)
        return Triple(length, crc, hash)
    }

    fun blake3(bytes: ByteArray): ByteArray {
        val digest = Blake3Digest(BLAKE3_DIGEST_BITS)
        digest.update(bytes, 0, bytes.size)
        val out = ByteArray(HASH_SIZE)
        digest.doFinal(out, 0)
        return out
    }

    fun crc32c(payload: ByteArray): Int =
        CRC32C().apply { update(payload, 0, payload.size) }.value.toInt()
}
