#include "TextureReplace.h"
#include "Log.h"
#include "Il2cppUtils.hpp"
#include "../il2cpp/il2cpp_symbols.hpp"
#include <fstream>
#include <filesystem>
#include <windows.h>

extern std::filesystem::path gakumasLocalPath;

namespace GakumasLocal::TextureReplace {
    // IL2CPP string structure
    struct Il2CppString {
        void* klass;
        void* monitor;
        int length;
        wchar_t chars[1];
    };
    
    // 资源映射表: assetId -> 本地文件路径
    std::map<std::string, std::string> g_assetMappings;
    
    // 待替换的请求映射表
    std::map<void*, PendingReplacement> g_pendingReplacements;
    
    // 纹理替换基础目录
    std::filesystem::path g_textureBaseDir;
    
    // IL2CPP API函数指针
    static void* (*il2cpp_domain_get)() = nullptr;
    static void** (*il2cpp_domain_get_assemblies)(void*, size_t*) = nullptr;
    static void* (*il2cpp_assembly_get_image)(void*) = nullptr;
    static void* (*il2cpp_class_from_name)(void*, const char*, const char*) = nullptr;
    static void* (*il2cpp_object_new)(void*) = nullptr;
    static void* (*il2cpp_class_get_method_from_name)(void*, const char*, int) = nullptr;
    static void* (*il2cpp_runtime_invoke)(void*, void*, void**, void**) = nullptr;
    static void* (*il2cpp_array_new)(void*, size_t) = nullptr;
    
    // 安全转换IL2CPP字符串为std::string
    std::string Il2CppStringToStdString(void* il2cppString) {
        if (!il2cppString) return "";
        
        if (IsBadReadPtr(il2cppString, sizeof(Il2CppString))) {
            return "";
        }
        
        Il2CppString* str = (Il2CppString*)il2cppString;
        
        if (str->length <= 0 || str->length > 1000) {
            return "";
        }
        
        if (IsBadReadPtr(str->chars, str->length * sizeof(wchar_t))) {
            return "";
        }
        
        int bufferSize = WideCharToMultiByte(CP_UTF8, 0, str->chars, str->length, nullptr, 0, nullptr, nullptr);
        if (bufferSize <= 0) return "";
        
        std::string result(bufferSize, 0);
        WideCharToMultiByte(CP_UTF8, 0, str->chars, str->length, &result[0], bufferSize, nullptr, nullptr);
        
        return result;
    }
    
    // 初始化IL2CPP API
    bool InitializeIL2CPPApi() {
        Log::Info("TextureReplace: Initializing IL2CPP API...");
        
        HMODULE hGameAssembly = GetModuleHandleA("GameAssembly.dll");
        if (!hGameAssembly) {
            Log::Error("TextureReplace: Failed to get GameAssembly.dll handle");
            return false;
        }
        
        il2cpp_domain_get = (void* (*)())GetProcAddress(hGameAssembly, "il2cpp_domain_get");
        il2cpp_domain_get_assemblies = (void** (*)(void*, size_t*))GetProcAddress(hGameAssembly, "il2cpp_domain_get_assemblies");
        il2cpp_assembly_get_image = (void* (*)(void*))GetProcAddress(hGameAssembly, "il2cpp_assembly_get_image");
        il2cpp_class_from_name = (void* (*)(void*, const char*, const char*))GetProcAddress(hGameAssembly, "il2cpp_class_from_name");
        il2cpp_object_new = (void* (*)(void*))GetProcAddress(hGameAssembly, "il2cpp_object_new");
        il2cpp_class_get_method_from_name = (void* (*)(void*, const char*, int))GetProcAddress(hGameAssembly, "il2cpp_class_get_method_from_name");
        il2cpp_runtime_invoke = (void* (*)(void*, void*, void**, void**))GetProcAddress(hGameAssembly, "il2cpp_runtime_invoke");
        il2cpp_array_new = (void* (*)(void*, size_t))GetProcAddress(hGameAssembly, "il2cpp_array_new");
        
        if (!il2cpp_domain_get || !il2cpp_domain_get_assemblies || !il2cpp_assembly_get_image || 
            !il2cpp_class_from_name || !il2cpp_object_new || !il2cpp_class_get_method_from_name ||
            !il2cpp_runtime_invoke || !il2cpp_array_new) {
            Log::Error("TextureReplace: Failed to get IL2CPP API functions");
            return false;
        }
        
        Log::Info("TextureReplace: IL2CPP API initialized successfully");
        return true;
    }
    
    // 初始化纹理替换系统
    bool Initialize() {
        Log::Info("TextureReplace: Initializing texture replacement system...");
        
        // 设置基础目录
        g_textureBaseDir = gakumasLocalPath / "textures";
        
        // 创建目录结构
        try {
            std::filesystem::create_directories(g_textureBaseDir);
            std::filesystem::create_directories(g_textureBaseDir / "comic" / "1ko");
            std::filesystem::create_directories(g_textureBaseDir / "comic" / "4ko");
            std::filesystem::create_directories(g_textureBaseDir / "general_report");
            std::filesystem::create_directories(g_textureBaseDir / "ui");
            std::filesystem::create_directories(g_textureBaseDir / "tutorial");
            Log::InfoFmt("TextureReplace: Created texture directories at: %s", g_textureBaseDir.string().c_str());
        }
        catch (const std::exception& e) {
            Log::ErrorFmt("TextureReplace: Failed to create directories: %s", e.what());
            return false;
        }
        
        // 初始化IL2CPP API
        if (!InitializeIL2CPPApi()) {
            return false;
        }
        
        // 加载资源映射配置
        if (!LoadAssetMappings()) {
            Log::Info("TextureReplace: No asset mappings loaded, texture replacement will be disabled");
            return false;
        }
        
        Log::Info("TextureReplace: Texture replacement system initialized successfully");
        return true;
    }
    
    // 加载资源映射配置
    bool LoadAssetMappings() {
        std::filesystem::path configPath = g_textureBaseDir / "asset_mapping.txt";
        
        if (!std::filesystem::exists(configPath)) {
            Log::InfoFmt("TextureReplace: Config file not found: %s", configPath.string().c_str());
            return false;
        }
        
        std::ifstream file(configPath);
        if (!file.is_open()) {
            Log::ErrorFmt("TextureReplace: Failed to open config file: %s", configPath.string().c_str());
            return false;
        }
        
        g_assetMappings.clear();
        std::string line;
        int count = 0;
        
        while (std::getline(file, line)) {
            // 跳过空行和注释
            if (line.empty() || line[0] == '#') continue;
            
            size_t equalPos = line.find('=');
            if (equalPos != std::string::npos) {
                std::string assetId = line.substr(0, equalPos);
                std::string localPath = line.substr(equalPos + 1);
                
                // 移除首尾空格
                while (!assetId.empty() && (assetId.back() == ' ' || assetId.back() == '\r')) assetId.pop_back();
                while (!localPath.empty() && (localPath.front() == ' ')) localPath.erase(0, 1);
                while (!localPath.empty() && (localPath.back() == ' ' || localPath.back() == '\r')) localPath.pop_back();
                
                // 转换为完整路径
                std::filesystem::path fullPath = g_textureBaseDir / localPath;
                g_assetMappings[assetId] = fullPath.string();
                count++;
            }
        }
        
        file.close();
        Log::InfoFmt("TextureReplace: Loaded %d asset mappings", count);
        return count > 0;
    }
    
    // 检查是否需要替换指定资源
    bool ShouldReplaceAsset(const std::string& assetName, std::string& replacementPath) {
        auto it = g_assetMappings.find(assetName);
        if (it != g_assetMappings.end()) {
            replacementPath = it->second;
            
            // 检查文件是否存在
            if (std::filesystem::exists(replacementPath)) {
                return true;
            }
            else {
                Log::InfoFmt("TextureReplace: Mapped file not found: %s", replacementPath.c_str());
            }
        }
        return false;
    }
    
    // 从文件加载图片数据
    bool LoadImageFile(const std::string& filePath, std::vector<unsigned char>& imageData) {
        FILE* file = nullptr;
        if (fopen_s(&file, filePath.c_str(), "rb") != 0 || !file) {
            Log::ErrorFmt("TextureReplace: Failed to open image file: %s", filePath.c_str());
            return false;
        }
        
        fseek(file, 0, SEEK_END);
        long fileSize = ftell(file);
        fseek(file, 0, SEEK_SET);
        
        if (fileSize <= 0) {
            fclose(file);
            Log::ErrorFmt("TextureReplace: Invalid file size: %ld", fileSize);
            return false;
        }
        
        imageData.resize(fileSize);
        size_t bytesRead = fread(imageData.data(), 1, fileSize, file);
        fclose(file);
        
        if (bytesRead != fileSize) {
            Log::ErrorFmt("TextureReplace: Failed to read complete file. Expected: %ld, Read: %zu", fileSize, bytesRead);
            return false;
        }
        
        Log::InfoFmt("TextureReplace: Loaded image file: %s (%ld bytes)", filePath.c_str(), fileSize);
        return true;
    }
    
    // 创建Unity Texture2D对象从图片数据
    void* CreateUnityTexture2DFromImage(const std::vector<unsigned char>& imageData, const std::string& fileName) {
        if (imageData.empty()) {
            Log::Error("TextureReplace: Empty image data");
            return nullptr;
        }
        
        Log::InfoFmt("TextureReplace: Creating Unity Texture2D from %s (%d bytes)", fileName.c_str(), (int)imageData.size());
        
        void* domain = il2cpp_domain_get();
        if (!domain) {
            Log::Error("TextureReplace: Failed to get IL2CPP domain");
            return nullptr;
        }
        
        size_t assemblyCount = 0;
        void** assemblies = il2cpp_domain_get_assemblies(domain, &assemblyCount);
        if (!assemblies) {
            Log::Error("TextureReplace: Failed to get assemblies");
            return nullptr;
        }
        
        void* texture2DClass = nullptr;
        void* imageConversionClass = nullptr;
        
        // 查找所需的类
        for (size_t i = 0; i < assemblyCount; i++) {
            void* assembly = assemblies[i];
            if (!assembly) continue;
            
            void* image = il2cpp_assembly_get_image(assembly);
            if (!image) continue;
            
            if (!texture2DClass) {
                texture2DClass = il2cpp_class_from_name(image, "UnityEngine", "Texture2D");
            }
            if (!imageConversionClass) {
                imageConversionClass = il2cpp_class_from_name(image, "UnityEngine", "ImageConversion");
            }
            
            if (texture2DClass && imageConversionClass) break;
        }
        
        if (!texture2DClass) {
            Log::Error("TextureReplace: Failed to find Texture2D class");
            return nullptr;
        }
        
        // 创建Texture2D对象
        void* texture2DObject = il2cpp_object_new(texture2DClass);
        if (!texture2DObject) {
            Log::Error("TextureReplace: Failed to create Texture2D object");
            return nullptr;
        }
        
        // 调用构造函数 (2x2, RGBA32)
        void* ctorMethod = il2cpp_class_get_method_from_name(texture2DClass, ".ctor", 2);
        if (ctorMethod) {
            try {
                int width = 2;
                int height = 2;
                void* ctorParams[2] = { &width, &height };
                void* ctorException = nullptr;
                
                il2cpp_runtime_invoke(ctorMethod, texture2DObject, ctorParams, &ctorException);
                if (ctorException) {
                    Log::InfoFmt("TextureReplace: Constructor exception: 0x%p", ctorException);
                }
            }
            catch (...) {
                Log::Info("TextureReplace: Exception during constructor call");
            }
        }
        
        // 如果有ImageConversion类,使用LoadImage方法加载实际图片数据
        if (imageConversionClass) {
            void* loadImageMethod = il2cpp_class_get_method_from_name(imageConversionClass, "LoadImage", 2);
            if (loadImageMethod) {
                try {
                    // 创建byte数组
                    void* byteArrayClass = nullptr;
                    for (size_t i = 0; i < assemblyCount; i++) {
                        void* assembly = assemblies[i];
                        if (!assembly) continue;
                        void* image = il2cpp_assembly_get_image(assembly);
                        if (!image) continue;
                        byteArrayClass = il2cpp_class_from_name(image, "System", "Byte");
                        if (byteArrayClass) break;
                    }
                    
                    if (byteArrayClass) {
                        void* byteArray = il2cpp_array_new(byteArrayClass, imageData.size());
                        if (byteArray) {
                            // 复制图片数据到数组
                            memcpy((char*)byteArray + 4 * sizeof(void*), imageData.data(), imageData.size());
                            
                            // 调用ImageConversion.LoadImage(texture2D, byteArray)
                            void* params[2] = { texture2DObject, byteArray };
                            void* exception = nullptr;
                            il2cpp_runtime_invoke(loadImageMethod, nullptr, params, &exception);
                            
                            if (exception) {
                                Log::InfoFmt("TextureReplace: LoadImage exception: 0x%p", exception);
                            }
                            else {
                                Log::InfoFmt("TextureReplace: Successfully loaded image into Texture2D: 0x%p", texture2DObject);
                                return texture2DObject;
                            }
                        }
                    }
                }
                catch (...) {
                    Log::Info("TextureReplace: Exception during LoadImage call");
                }
            }
        }
        
        Log::InfoFmt("TextureReplace: Created basic Texture2D object: 0x%p", texture2DObject);
        return texture2DObject;
    }
    
    // 加载自定义纹理
    void* LoadCustomTexture(const std::string& filePath) {
        std::vector<unsigned char> imageData;
        if (!LoadImageFile(filePath, imageData)) {
            return nullptr;
        }
        
        std::filesystem::path path(filePath);
        return CreateUnityTexture2DFromImage(imageData, path.filename().string());
    }
    
    // 清理待处理的替换请求
    void CleanupPendingReplacements() {
        unsigned long currentTime = GetTickCount();
        
        for (auto it = g_pendingReplacements.begin(); it != g_pendingReplacements.end();) {
            if (currentTime - it->second.timestamp > 60000) { // 超过60秒的请求
                Log::InfoFmt("TextureReplace: Cleaning up expired replacement request: 0x%p", it->first);
                it = g_pendingReplacements.erase(it);
            }
            else {
                ++it;
            }
        }
    }
}
