package com.korancrew.brizzi.hce

/**
 * Struktur hasil parsing APDU:
 * - CLA/INS/P1/P2
 * - Lc (opsional), data (opsional), Le (opsional)
 * - raw bytes dan representasi hex
 */
data class ParsedApdu(
    val cla: Int,
    val ins: Int,
    val p1: Int,
    val p2: Int,
    val lc: Int?,
    val data: ByteArray,
    val le: Int?,
    val raw: ByteArray,
    val rawHex: String,
) {
    val hasData: Boolean = data.isNotEmpty()
    val isCase1: Boolean = lc == null && le == null
    val isCase2: Boolean = lc == null && le != null
    val isCase3: Boolean = lc != null && le == null
    val isCase4: Boolean = lc != null && le != null
}

class ApduParseException(message: String) : IllegalArgumentException(message)

/**
 * Parser APDU minimal untuk jalur HCE Brizzi.
 * Mendukung case 1/2/3/4:
 * - 4 byte + (opsional) data + (opsional) Le.
 */
object ApduParser {
    fun parse(bytes: ByteArray): ParsedApdu {
        if (bytes.isEmpty()) throw ApduParseException("APDU empty")
        if (bytes.size < 4) {
            return ParsedApdu(
                cla = bytes[0].toInt() and 0xFF,
                ins = if (bytes.size >= 2) bytes[1].toInt() and 0xFF else 0,
                p1 = if (bytes.size >= 3) bytes[2].toInt() and 0xFF else 0,
                p2 = if (bytes.size >= 4) bytes[3].toInt() and 0xFF else 0,
                lc = if (bytes.isNotEmpty()) 0 else null,
                data = ByteArray(0),
                le = null,
                raw = bytes,
                rawHex = bytes.toHex(),
            )
        }

        val cla = bytes[0].toInt() and 0xFF
        val ins = bytes[1].toInt() and 0xFF
        val p1 = bytes[2].toInt() and 0xFF
        val p2 = bytes[3].toInt() and 0xFF
        var index = 4
        val remaining = bytes.size - index

        val (lc, data, le) = when {
            remaining == 0 -> ParsedPayload(null, ByteArray(0), null)
            remaining == 1 -> ParsedPayload(null, ByteArray(0), bytes[4].toInt() and 0xFF)
            else -> {
                val lcValue = bytes[index].toInt() and 0xFF
                index += 1
                if (index + lcValue > bytes.size) {
                    throw ApduParseException("Lc exceeds APDU length")
                }

                val data = if (lcValue == 0) ByteArray(0) else bytes.copyOfRange(index, index + lcValue)
                index += lcValue

                when {
                    index == bytes.size -> ParsedPayload(lcValue, data, null)
                    index == bytes.size - 1 -> ParsedPayload(lcValue, data, bytes[index].toInt() and 0xFF)
                    else -> throw ApduParseException("Unexpected trailing bytes")
                }
            }
        }

        return ParsedApdu(
            cla = cla,
            ins = ins,
            p1 = p1,
            p2 = p2,
            lc = lc,
            data = data,
            le = le,
            raw = bytes,
            rawHex = bytes.toHex(),
        )
    }
}

private data class ParsedPayload(
    val lc: Int?,
    val data: ByteArray,
    val le: Int?,
)
