#include "sys_util.h"
#include <string>
#include <locale>
#include <cassert>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <unicode/ucnv.h>
#include <unicode/ustring.h>
#include <stdexcept>
#include <vector>
#include <regex>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <windows.h>

namespace zsy
{
    std::string SysUtil::WORK_DIR = []() -> std::string
    {
        WCHAR wstr[MAX_PATH]{};
        if (!GetModuleFileName(nullptr, wstr, MAX_PATH))
        {
            throw std::runtime_error("运行目录获取失败");
        }

        auto str = str_w_a(wstr);
        size_t lastSlash = str.find_last_of("\\/");
        return lastSlash == std::string::npos ? str : str.substr(0, lastSlash);
    }();

    std::string SysUtil::HOME_DIR = []() -> std::string
    {
        if (WORK_DIR.ends_with("bin"))
        {
            size_t lastSlash = WORK_DIR.find_last_of("\\/");
            return lastSlash == std::string::npos ? WORK_DIR : WORK_DIR.substr(0, lastSlash);
        }
        return WORK_DIR;
    }();

    // UTF-8字符串转宽字符串
    std::wstring SysUtil::str_a_w(const std::string &astr, const char *encode)
    {
        UErrorCode status = U_ZERO_ERROR;

        // 使用unique_ptr管理转换器资源，确保异常安全
        std::unique_ptr<UConverter, decltype(&ucnv_close)> converter(
            ucnv_open(encode, &status),
            &ucnv_close
        );

        if (U_FAILURE(status))
        {
            throw std::runtime_error("Failed to open converter: " + std::to_string(status));
        }

        // 第一阶段：获取所需缓冲区大小
        status = U_ZERO_ERROR;
        int32_t targetCapacity = ucnv_toUChars(
            converter.get(), nullptr, 0, astr.c_str(),
            static_cast<int32_t>(astr.length()), &status
        );

        if (status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(status))
        {
            throw std::runtime_error("Failed to calculate target length: " + std::to_string(status));
        }

        // 分配足够空间
        std::vector<UChar> buffer;
        try
        {
            buffer.resize(targetCapacity);
        } catch (const std::bad_alloc &)
        {
            throw std::runtime_error("Memory allocation failed");
        }

        // 第二阶段：实际转换
        status = U_ZERO_ERROR;
        int32_t actualLength = ucnv_toUChars(
            converter.get(),
            buffer.data(),
            targetCapacity,
            astr.c_str(),
            static_cast<int32_t>(astr.length()),
            &status
        );

        if (U_FAILURE(status))
        {
            throw std::runtime_error("Conversion failed: " + std::to_string(status));
        }

        // 转换为wstring，考虑平台差异
        std::wstring result;

        static_assert(sizeof(wchar_t) == sizeof(UChar), "wchar_t size mismatch on Windows");
        result.assign(reinterpret_cast<const wchar_t *>(buffer.data()), actualLength);

        return result;
    }

    // 宽字符串转UTF-8字符串
    std::string SysUtil::str_w_a(const std::wstring &wstr, const char *encode)
    {
        UErrorCode status = U_ZERO_ERROR;

        // 使用unique_ptr管理转换器资源，确保异常安全
        const std::unique_ptr<UConverter, decltype(&ucnv_close)> converter(
            ucnv_open(encode, &status),
            &ucnv_close
        );

        if (U_FAILURE(status))
        {
            throw std::runtime_error("Failed to open converter");
        }

        // 安全的类型转换 - 假设wchar_t在Windows上是UTF-16，在其他平台可能需要不同处理
        static_assert(sizeof(wchar_t) == sizeof(UChar) || sizeof(wchar_t) == sizeof(UChar32),
                      "wchar_t size not compatible with ICU UChar types");

        const auto *ustr = reinterpret_cast<const UChar *>(wstr.c_str());
        const auto srcLength = static_cast<int32_t>(wstr.length());

        // 第一阶段：获取所需缓冲区大小
        status = U_ZERO_ERROR;
        int32_t targetCapacity = ucnv_fromUChars(
            converter.get(), nullptr, 0, ustr, srcLength, &status
        );

        if (status != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(status))
        {
            throw std::runtime_error("Failed to calculate target length: " + std::to_string(status));
        }

        // 分配足够空间 (+1不是必须的，因为ucnv_fromUChars不包含null终止符)
        std::string result;
        try
        {
            result.resize(targetCapacity);
        } catch (const std::bad_alloc &)
        {
            throw std::runtime_error("Memory allocation failed");
        }

        // 第二阶段：实际转换
        status = U_ZERO_ERROR;
        int32_t actualLength = ucnv_fromUChars(
            converter.get(),
            &result[0],
            targetCapacity,
            ustr,
            srcLength,
            &status
        );

        if (U_FAILURE(status))
        {
            throw std::runtime_error("Conversion failed: " + std::to_string(status));
        }

        // 调整大小为实际转换后的长度
        result.resize(actualLength);

        return result;
    }

    // UTF-8字符串转宽字符串
    std::shared_ptr<wchar_t[]> SysUtil::ch_a_w(const char *ach)
    {
        if (ach == nullptr) return nullptr;

        std::string astr(ach);
        std::wstring wstr = str_a_w(astr);

        size_t size = wstr.size() + 1;
        auto result = std::unique_ptr <wchar_t[]>(new wchar_t[size], std::default_delete<wchar_t[]>());
        wcscpy_s(result.get(), size, wstr.c_str());
        return result;
    }

    // 宽字符串转UTF-8字符串
    std::shared_ptr<char[]> SysUtil::ch_w_a(const wchar_t *wch)
    {
        if (wch == nullptr) return nullptr;

        std::wstring wstr(wch);
        std::string utf8 = str_w_a(wstr);

        size_t size = utf8.size() + 1;
        auto result = std::unique_ptr<char[]>(new char[size], std::default_delete<char[]>());
        strcpy_s(result.get(), size, utf8.c_str());
        return result;
    }

    std::shared_ptr<char[]> SysUtil::ch_vlt(const char *ach)
    {
        if (ach == nullptr) return nullptr;
        size_t size = strlen(ach) + 1;
        auto result = std::make_shared<char[]>(size);
        strcpy_s(result.get(), size, ach);
        return result;
    }

    std::shared_ptr<wchar_t[]> SysUtil::ch_vlt(const wchar_t *wch)
    {
        if (wch == nullptr) return nullptr;
        size_t size = wcslen(wch) + 1;
        auto result = std::make_shared<wchar_t[]>(size);
        wcscpy_s(result.get(), size, wch);
        return result;
    }

    std::tuple<bool, uint64_t, std::string> SysUtil::getError()
    {
        DWORD errorCode = GetLastError();
        if (errorCode == 0) return std::make_tuple(false, 0, "");

        LPVOID lpMsgBuf;
        DWORD bufLen = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr,
            errorCode,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            reinterpret_cast<LPTSTR>(&lpMsgBuf),
            0, nullptr
        );

        if (bufLen == 0) return std::make_tuple(true, errorCode, "");
        auto msg = str_w_a(static_cast<LPTSTR>(lpMsgBuf));
        LocalFree(lpMsgBuf);
        return std::make_tuple(true, errorCode, std::regex_replace(msg, std::regex("\\s"), ""));
    }

    std::string SysUtil::toHex(uint64_t value, int width, bool uppercase)
    {
        std::stringstream ss;

        ss << std::hex;
        if (uppercase) ss << std::uppercase;
        if (width > 0) ss << std::setw(width) << std::setfill('0');

        ss << value;
        return ss.str();
    }

    std::string SysUtil::sha1(const std::string &data)
    {
        unsigned char digest[SHA_DIGEST_LENGTH];
        SHA1(reinterpret_cast<const unsigned char *>(data.c_str()), data.size(), digest);

        std::ostringstream out;
        out << std::hex << std::setfill('0');
        for (unsigned char c: digest)
        {
            out << std::setw(2) << static_cast<int>(c);
        }
        return out.str();
    }

    std::string SysUtil::hmac_sha1(const std::string &key, const std::string &data)
    {
        unsigned char digest[EVP_MAX_MD_SIZE];

        unsigned int digest_len = 0;

        // 计算HMAC-SHA1
        const unsigned char *digest_ptr = HMAC(
            EVP_sha1(),
            key.c_str(),
            static_cast<int>(key.length()),
            reinterpret_cast<const unsigned char *>(data.c_str()),
            data.length(),
            digest,
            &digest_len
        );

        if (!digest_ptr)
        {
            throw std::runtime_error("HMAC-SHA1 计算失败");
        }

        return base64_encode(digest, digest_len);
    }

    std::string SysUtil::base64_encode(const unsigned char *data, const size_t length)
    {
        if (data == nullptr || length == 0) return {};

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

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

        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);

        // 写入数据并编码
        const int write_result = BIO_write(bio, data, static_cast<int>(length));
        if (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;
    }

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

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

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

        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);
    }

    void SysUtil::createDirs(const std::filesystem::path &path)
    {
        try
        {
            if (!std::filesystem::exists(path))
            {
                bool created = std::filesystem::create_directories(path);

                if (!created)
                {
                    throw std::runtime_error("创建文件夹失败");
                }
            }
        } catch (const std::filesystem::filesystem_error &e)
        {
            throw std::runtime_error("文件系统错误: " + std::string(e.what()));
        } catch (const std::exception &e)
        {
            throw std::runtime_error("创建文件夹时发生错误: " + std::string(e.what()));
        } catch (...)
        {
            throw std::runtime_error("创建文件夹时发生未知错误");
        }
    }

}
