#ifndef DEVICE_CTRL_BASE64_UTIL_H
#define DEVICE_CTRL_BASE64_UTIL_H

#include <iomanip>
#include <ios>
#include <string>
#include <vector>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>


namespace zsy::Base64
{
    inline std::string encode(const unsigned char *data, const size_t length)
    {
        if (data == nullptr || length == 0) return {};

        // 创建Base64编码的BIO链
        BUF_MEM *bufferPtr;

        BIO *b64 = BIO_new(BIO_f_base64());
        if (!b64)
        {
            throw std::runtime_error("base64 编码失败，无法分配内存");
        }

        BIO *bio = BIO_new(BIO_s_mem());
        if (!bio)
        {
            BIO_free(b64);
            throw std::runtime_error("base64 编码失败，无法分配内存");
        }

        bio = BIO_push(b64, bio);
        BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);

        // 写入数据并编码
        if (const int write_result = BIO_write(bio, data, static_cast<int>(length)); write_result <= 0)
        {
            BIO_free_all(bio);
            throw std::runtime_error("base64 编码失败，写入数据失败");
        }

        if (BIO_flush(bio) != 1)
        {
            BIO_free_all(bio);
            throw std::runtime_error("base64 编码失败，刷新缓冲区失败");
        }

        // 获取编码结果
        BIO_get_mem_ptr(bio, &bufferPtr);
        std::string result(bufferPtr->data, bufferPtr->length);

        // 释放资源
        BIO_free_all(bio);
        return result;
    }

    inline std::string encode(const std::string &data)
    {
        return encode(
            reinterpret_cast<const unsigned char *>(data.data()),
            data.length()
        );
    }

    inline std::string decode(const unsigned char *data, const size_t length)
    {
        if (data == nullptr || length == 0) return {};
        // 创建Base64解码的BIO链
        BUF_MEM *bufferPtr;

        BIO *b64 = BIO_new(BIO_f_base64());
        if (!b64)
        {
            throw std::runtime_error("base64 解码失败，无法创建分配内存");
        }

        // 不忽略行末符号
        BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

        BIO *bio = BIO_new_mem_buf(data, length);
        if (!bio)
        {
            BIO_free(b64);
            throw std::runtime_error("base64 解码失败，无法分配内存");
        }

        bio = BIO_push(b64, bio);

        // 计算解码后的估计长度
        const size_t estimated_length = length * 3 / 4 + 1;
        std::vector<char> buffer(estimated_length);

        // 执行解码
        const int decoded_length = BIO_read(bio, buffer.data(), estimated_length - 1);
        if (decoded_length <= 0)
        {
            BIO_free_all(bio);
            throw std::runtime_error("base64 解码失败，读取数据失败");
        }

        // 释放资源
        BIO_free_all(bio);

        // 返回解码后的字符串
        return std::string(buffer.data(), decoded_length);
    }

    inline std::string decode(const std::string &data)
    {
        return decode(
            reinterpret_cast<const unsigned char *>(data.data()),
            data.length()
        );
    }
}

#endif // DEVICE_CTRL_BASE64_UTIL_H