// resource_loader.cpp
// Resource loader implementation

#include "resource_loader.hpp"

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

namespace Resource {

    // Get singleton instance
    auto Loader::get() -> Loader& {
        static Loader instance_;
        return instance_;
    }

    // Initialize with a pack file
    auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
        -> bool {
        if (initialized_) {
            std::cout << "Loader: Already initialized\n";
            return true;
        }

        fallback_to_files_ = enable_fallback;

        // Try to load the pack file
        if (!pack_file.empty() && fileExistsOnFilesystem(pack_file)) {
            std::cout << "Loader: Loading pack file: " << pack_file << '\n';
            resource_pack_ = std::make_unique<Pack>();
            if (resource_pack_->loadPack(pack_file)) {
                std::cout << "Loader: Pack loaded successfully\n";
                initialized_ = true;
                return true;
            }
            std::cerr << "Loader: Failed to load pack file\n";
            resource_pack_.reset();
        } else {
            std::cout << "Loader: Pack file not found: " << pack_file << '\n';
        }

        // If pack loading failed and fallback is disabled, fail
        if (!fallback_to_files_) {
            std::cerr << "Loader: Pack required but not found (fallback disabled)\n";
            return false;
        }

        // Otherwise, fallback to filesystem
        std::cout << "Loader: Using filesystem fallback\n";
        initialized_ = true;
        return true;
    }

    // Load a resource
    auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
        if (!initialized_) {
            std::cerr << "Loader: Not initialized\n";
            return {};
        }

        // Try pack first if available
        if (resource_pack_ && resource_pack_->isLoaded()) {
            if (resource_pack_->hasResource(filename)) {
                auto data = resource_pack_->getResource(filename);
                if (!data.empty()) {
                    return data;
                }
                std::cerr << "Loader: Failed to extract from pack: " << filename
                          << '\n';
            }
        }

        // Fallback to filesystem if enabled
        if (fallback_to_files_) {
            return loadFromFilesystem(filename);
        }

        std::cerr << "Loader: Resource not found: " << filename << '\n';
        return {};
    }

    // Check if a resource exists
    auto Loader::resourceExists(const std::string& filename) -> bool {
        if (!initialized_) {
            return false;
        }

        // Check pack first
        if (resource_pack_ && resource_pack_->isLoaded()) {
            if (resource_pack_->hasResource(filename)) {
                return true;
            }
        }

        // Check filesystem if fallback enabled
        if (fallback_to_files_) {
            return fileExistsOnFilesystem(filename);
        }

        return false;
    }

    // Check if pack is loaded
    auto Loader::isPackLoaded() const -> bool {
        return resource_pack_ && resource_pack_->isLoaded();
    }

    // Get pack statistics
    auto Loader::getPackResourceCount() const -> size_t {
        if (resource_pack_ && resource_pack_->isLoaded()) {
            return resource_pack_->getResourceCount();
        }
        return 0;
    }

    // Cleanup
    void Loader::shutdown() {
        resource_pack_.reset();
        initialized_ = false;
        std::cout << "Loader: Shutdown complete\n";
    }

    // Load from filesystem
    auto Loader::loadFromFilesystem(const std::string& filepath)
        -> std::vector<uint8_t> {
        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);
        if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
            std::cerr << "Loader: Failed to read file: " << filepath << '\n';
            return {};
        }

        return data;
    }

    // Check if file exists on filesystem
    auto Loader::fileExistsOnFilesystem(const std::string& filepath) -> bool {
        return std::filesystem::exists(filepath);
    }

    // Validate pack integrity
    auto Loader::validatePack() const -> bool {
        if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
            std::cerr << "Loader: Cannot validate - pack not loaded\n";
            return false;
        }

        // Calculate pack checksum
        uint32_t checksum = resource_pack_->calculatePackChecksum();

        if (checksum == 0) {
            std::cerr << "Loader: Pack checksum is zero (invalid)\n";
            return false;
        }

        std::cout << "Loader: Pack checksum: 0x" << std::hex << checksum << std::dec
                  << '\n';
        std::cout << "Loader: Pack validation successful\n";
        return true;
    }

    // Load assets.yaml from pack
    auto Loader::loadAssetsConfig() const -> std::string {
        if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
            std::cerr << "Loader: Cannot load assets config - pack not loaded\n";
            return "";
        }

        // Try to load config/assets.yaml from pack
        std::string config_path = "config/assets.yaml";

        if (!resource_pack_->hasResource(config_path)) {
            std::cerr << "Loader: assets.yaml not found in pack: " << config_path << '\n';
            return "";
        }

        auto data = resource_pack_->getResource(config_path);
        if (data.empty()) {
            std::cerr << "Loader: Failed to load assets.yaml from pack\n";
            return "";
        }

        // Convert bytes to string
        std::string config_content(data.begin(), data.end());
        std::cout << "Loader: Loaded assets.yaml from pack (" << data.size()
                  << " bytes)\n";

        return config_content;
    }

}  // namespace Resource
