// resource_helper.cpp
// Resource helper implementation

#include "resource_helper.hpp"

#include <algorithm>
#include <filesystem>
#include <fstream>
#include <iostream>

#include "resource_loader.hpp"

namespace Resource::Helper {

    static bool resource_system_initialized = false;

    // Initialize the resource system
    auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback)
        -> bool {
        if (resource_system_initialized) {
            std::cout << "ResourceHelper: Already initialized\n";
            return true;
        }

        std::cout << "ResourceHelper: Initializing with pack: " << pack_file << '\n';
        std::cout << "ResourceHelper: Fallback enabled: " << (enable_fallback ? "Yes" : "No")
                  << '\n';

        bool success = Loader::get().initialize(pack_file, enable_fallback);
        if (success) {
            resource_system_initialized = true;
            std::cout << "ResourceHelper: Initialization successful\n";
        } else {
            std::cerr << "ResourceHelper: Initialization failed\n";
        }

        return success;
    }

    // Shutdown the resource system
    void shutdownResourceSystem() {
        if (resource_system_initialized) {
            Loader::get().shutdown();
            resource_system_initialized = false;
            std::cout << "ResourceHelper: Shutdown complete\n";
        }
    }

    // Load a file
    auto loadFile(const std::string& filepath) -> std::vector<uint8_t> {
        if (!resource_system_initialized) {
            std::cerr << "ResourceHelper: System not initialized, loading from filesystem\n";
            // Fallback to direct filesystem access
            std::ifstream file(filepath, std::ios::binary | std::ios::ate);
            if (!file) {
                return {};
            }
            std::streamsize file_size = file.tellg();
            file.seekg(0, std::ios::beg);
            std::vector<uint8_t> data(file_size);
            file.read(reinterpret_cast<char*>(data.data()), file_size);
            return data;
        }

        // Determine if we should use the pack
        if (shouldUseResourcePack(filepath)) {
            // Convert to pack path
            std::string pack_path = getPackPath(filepath);

            // Try to load from pack
            auto data = Loader::get().loadResource(pack_path);
            if (!data.empty()) {
                return data;
            }

            // If pack loading failed, try filesystem as fallback
            std::cerr << "ResourceHelper: Pack failed for " << pack_path
                      << ", trying filesystem\n";
        }

        // Load from filesystem
        return Loader::get().loadResource(filepath);
    }

    // Check if a file exists
    auto fileExists(const std::string& filepath) -> bool {
        if (!resource_system_initialized) {
            return std::filesystem::exists(filepath);
        }

        // Check pack if appropriate
        if (shouldUseResourcePack(filepath)) {
            std::string pack_path = getPackPath(filepath);
            if (Loader::get().resourceExists(pack_path)) {
                return true;
            }
        }

        // Check filesystem
        return std::filesystem::exists(filepath);
    }

    // Convert asset path to pack path
    auto getPackPath(const std::string& asset_path) -> std::string {
        std::string path = asset_path;

        // Convert backslashes to forward slashes
        std::ranges::replace(path, '\\', '/');

        // If it's an absolute path containing "/data/", extract everything after "/data/"
        // This handles paths like: /Users/sergio/.../data/palette/file.pal -> palette/file.pal
        size_t data_pos = path.find("/data/");
        if (data_pos != std::string::npos) {
            return path.substr(data_pos + 6);  // +6 to skip "/data/"
        }

        // Remove leading slashes
        while (!path.empty() && path[0] == '/') {
            path = path.substr(1);
        }

        // Remove "./" prefix if present
        if (path.starts_with("./")) {
            path = path.substr(2);
        }

        // Remove "../" prefixes (for macOS bundle paths in development)
        while (path.starts_with("../")) {
            path = path.substr(3);
        }

        // Remove "Resources/" prefix if present (for macOS bundle)
        const std::string RESOURCES_PREFIX = "Resources/";
        if (path.starts_with(RESOURCES_PREFIX)) {
            path = path.substr(RESOURCES_PREFIX.length());
        }

        // Remove "data/" prefix if present
        const std::string DATA_PREFIX = "data/";
        if (path.starts_with(DATA_PREFIX)) {
            path = path.substr(DATA_PREFIX.length());
        }

        return path;
    }

    // Check if file should use resource pack
    auto shouldUseResourcePack(const std::string& filepath) -> bool {
        std::string path = filepath;
        std::ranges::replace(path, '\\', '/');

        // Don't use pack for most config files (except config/assets.yaml which is loaded
        // directly via Loader::loadAssetsConfig() in release builds)
        if (path.find("config/") != std::string::npos) {
            return false;
        }

        // Use pack for data files
        if (path.find("data/") != std::string::npos) {
            return true;
        }

        // Check if it looks like a data file (has common extensions)
        if (path.find(".ogg") != std::string::npos || path.find(".wav") != std::string::npos ||
            path.find(".gif") != std::string::npos || path.find(".png") != std::string::npos ||
            path.find(".pal") != std::string::npos || path.find(".yaml") != std::string::npos ||
            path.find(".txt") != std::string::npos || path.find(".glsl") != std::string::npos) {
            return true;
        }

        return false;
    }

    // Check if pack is loaded
    auto isPackLoaded() -> bool {
        if (!resource_system_initialized) {
            return false;
        }
        return Loader::get().isPackLoaded();
    }

}  // namespace Resource::Helper
