#pragma once

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <errno.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <direct.h>
#endif

#include "minizip/unzip.h"
#include "GakumasLocalify/Log.h"

// 辅助函数：递归创建目录
static bool CreateDirectoryRecursively(const std::string& dir) {
    if (dir.empty())
        return false;

    // 尝试创建目录
#ifdef _WIN32
    int ret = _mkdir(dir.c_str());
#else
    int ret = mkdir(dir.c_str(), 0755);
#endif
    if (ret == 0 || errno == EEXIST)
        return true;

    // 如果创建失败，尝试先创建父目录
    size_t pos = dir.find_last_of("/\\");
    if (pos != std::string::npos) {
        std::string parentDir = dir.substr(0, pos);
        if (!CreateDirectoryRecursively(parentDir))
            return false;
#ifdef _WIN32
        ret = _mkdir(dir.c_str());
#else
        ret = mkdir(dir.c_str(), 0755);
#endif
        return (ret == 0 || errno == EEXIST);
    }
    return false;
}

// 解压缩函数
static bool UnzipFile(const std::string& zipPath, const std::string& destinationFolder) {
    // 打开zip文件
    unzFile zipfile = unzOpen(zipPath.c_str());
    if (zipfile == nullptr) {
        GakumasLocal::Log::ErrorFmt( "Can't open zip file: %s", zipPath.c_str());
        return false;
    }

    int ret = unzGoToFirstFile(zipfile);
    if (ret != UNZ_OK) {
        GakumasLocal::Log::ErrorFmt("Can't read first file %s", zipPath.c_str());
        unzClose(zipfile);
        return false;
    }

    // 遍历zip内的每个文件
    do {
        char filename[512] = { 0 };
        unz_file_info fileInfo;
        ret = unzGetCurrentFileInfo(zipfile, &fileInfo,
            filename, sizeof(filename),
            nullptr, 0, nullptr, 0);
        if (ret != UNZ_OK) {
            GakumasLocal::Log::ErrorFmt("Read ZIP File Info Error");
            unzClose(zipfile);
            return false;
        }

        std::string filePath = filename;
        std::string fullPath = destinationFolder;
        // 保证目标目录以路径分隔符结尾
        if (fullPath.back() != '/' && fullPath.back() != '\\') {
            fullPath += "/";
        }
        fullPath += filePath;

        // 判断是否为目录（目录条目通常以'/'结尾）
        if (!filePath.empty() && (filePath.back() == '/' || filePath.back() == '\\')) {
            // 创建目录
            if (!CreateDirectoryRecursively(fullPath)) {
                GakumasLocal::Log::ErrorFmt("Create Dir Failed: %s", fullPath.c_str());
                unzClose(zipfile);
                return false;
            }
        }
        else {
            // 对于文件，先确保其上级目录存在
            size_t pos = fullPath.find_last_of("/\\");
            if (pos != std::string::npos) {
                std::string directory = fullPath.substr(0, pos);
                if (!CreateDirectoryRecursively(directory)) {
                    GakumasLocal::Log::ErrorFmt("Create Dir Failed: %s", directory.c_str());
                    unzClose(zipfile);
                    return false;
                }
            }

            // 打开zip中文件
            ret = unzOpenCurrentFile(zipfile);
            if (ret != UNZ_OK) {
                GakumasLocal::Log::ErrorFmt("Open file in zip failed: %s", filePath.c_str());
                unzClose(zipfile);
                return false;
            }

            // 在目标路径上创建新文件
            FILE* outFile = fopen(fullPath.c_str(), "wb");
            if (outFile == nullptr) {
                GakumasLocal::Log::ErrorFmt("Can't create output file: %s", fullPath.c_str());
                unzCloseCurrentFile(zipfile);
                unzClose(zipfile);
                return false;
            }

            // 读取数据并写入文件
            const int bufferSize = 8192;
            std::vector<char> buffer(bufferSize);
            int bytesRead = 0;
            do {
                bytesRead = unzReadCurrentFile(zipfile, buffer.data(), bufferSize);
                if (bytesRead < 0) {
                    GakumasLocal::Log::ErrorFmt("Read File Error: %s", filePath.c_str());
                    fclose(outFile);
                    unzCloseCurrentFile(zipfile);
                    unzClose(zipfile);
                    return false;
                }
                if (bytesRead > 0) {
                    fwrite(buffer.data(), 1, bytesRead, outFile);
                }
            } while (bytesRead > 0);

            fclose(outFile);
            unzCloseCurrentFile(zipfile);
        }

        ret = unzGoToNextFile(zipfile);
    } while (ret == UNZ_OK);

    unzClose(zipfile);
    return true;
}
