import t, c


# ==============================================
# Base64 Encoder & Decoder, pure bare-metal implementation
# ==============================================
# Base64 encoding lookup table
b64_tab: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

# Base64 反向解码表，映射字符到索引值
b64_dec_tab: t.CArray[t.CInt8T, 80] = [
    62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
    -1, -1, -1, -1, -1, -1, -1, 0,   1,  2,  3,  4,  5,  6,  7,  8, 9,
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
    -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
]

# * @brief  Base64 encoding
# * @param  s: Input binary data
# * @param  out: Output buffer for Base64 string
# * @retval Length of encoded string
def b64encode(s: str, out: str) -> t.CSizeT:
    _s = t.CUInt8T(s, t.CPtr)
    length: t.CSizeT = len(s)
    i: t.CSizeT = 0
    j: t.CSizeT = 0
    val: t.CUInt32T = 0
    # Process input in groups of 3 bytes, produce 4 Base64 characters
    for i in range(0, length, 3):
        # Assemble 24-bit chunk
        val = ((t.CUInt32T(_s[i + 0]) << 16                           ) |
               (t.CUInt32T(_s[i + 1]) <<  8 if (i + 1 < length) else 0) |
               (t.CUInt32T(_s[i + 2]) <<  0 if (i + 2 < length) else 0))
        # Split into four 6-bit values for table lookup
        out[j + 0] = b64_tab[(val >> 18) & 0x3F]
        out[j + 1] = b64_tab[(val >> 12) & 0x3F]
        out[j + 2] = b64_tab[(val >>  6) & 0x3F] if (i + 1 < length) else '='
        out[j + 3] = b64_tab[(val >>  0) & 0x3F] if (i + 2 < length) else '='
        j += 4
    out[j] = '\0'  # Null terminator for C-style string
    return j


# * @brief  Base64 decoding
# * @param  s: Base64 encoded string
# * @param  out: Output binary buffer
# * @retval Length of decoded binary data
def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT:
    length: t.CSizeT = len(s)
    i:      t.CSizeT = 0
    j:      t.CSizeT = 0
    val:    t.CUInt32T = 0
    c:      t.CInt
    # Restore 3 bytes from every 4 Base64 characters
    for i in range(0, length, 4):
        if s[i] == '=':
            break
        val = 0
        # Parse 6-bit values sequentially
        c = s[i] - 43
        val |= (b64_dec_tab[c] & 0x3F) << 18
        c = s[i+1] - 43
        val |= (b64_dec_tab[c] & 0x3F) << 12
        c = s[i+2] - 43
        if s[i+2] != '=':
            val |= (b64_dec_tab[c] & 0x3F) << 6
        c = s[i+3] - 43
        if s[i+3] != '=':
            val |= (b64_dec_tab[c] & 0x3F)
        # Write recovered bytes
        out[j] = (val >> 16) & 0xFF
        j += 1
        if s[i+2] != '=':
            out[j] = (val >> 8) & 0xFF
            j += 1
        if s[i+3] != '=':
            out[j] = val & 0xFF
            j += 1
    return j
