#include "asset.h"
#include <SDL3/SDL_log.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError
#include <algorithm>      // Para find_if, max
#include <fstream>        // Para basic_ifstream, ifstream
#include <string>         // Para allocator, string, char_traits, operator+
#include "utils.h"        // Para getFileName

// Añade un elemento a la lista
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute)
{
    file_list_.emplace_back(absolute ? file : executable_path_ + file, type, required);
    longest_name_ = std::max(longest_name_, static_cast<int>(file_list_.back().file.size()));
}

// Devuelve la ruta completa a un fichero a partir de una cadena
std::string Asset::get(const std::string &text) const
{
    auto it = std::find_if(file_list_.begin(), file_list_.end(),
                           [&text](const auto &f)
                           {
                               return getFileName(f.file) == text;
                           });

    if (it != file_list_.end())
    {
        return it->file;
    }
    else
    {
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str());
        return "";
    }
}

// Comprueba que existen todos los elementos
bool Asset::check() const
{
    bool success = true;

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES");

    // Comprueba la lista de ficheros clasificándolos por tipo
    for (int type = 0; type < static_cast<int>(AssetType::MAX_ASSET_TYPE); ++type)
    {
        // Comprueba si hay ficheros de ese tipo
        bool any = false;

        for (const auto &f : file_list_)
        {
            if (f.required && f.type == static_cast<AssetType>(type))
            {
                any = true;
            }
        }

        // Si hay ficheros de ese tipo, comprueba si existen
        if (any)
        {
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast<AssetType>(type)).c_str());

            for (const auto &f : file_list_)
            {
                if (f.required && f.type == static_cast<AssetType>(type))
                {
                    success &= checkFile(f.file);
                }
            }
            if (success)
                SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "   All files are OK.");
        }
    }

    // Resultado
    if (success)
    {
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES COMPLETED.\n");
    }
    else
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES FAILED.\n");
    }

    return success;
}

// Comprueba que existe un fichero
bool Asset::checkFile(const std::string &path) const
{
    std::ifstream file(path);
    bool success = file.good();
    file.close();

    if (!success)
    {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Checking file: %s [ ERROR ]", getFileName(path).c_str());
    }

    return success;
}

// Devuelve el nombre del tipo de recurso
std::string Asset::getTypeName(AssetType type) const
{
    switch (type)
    {
    case AssetType::BITMAP:
        return "BITMAP";
    case AssetType::MUSIC:
        return "MUSIC";
    case AssetType::SOUND:
        return "SOUND";
    case AssetType::FONT:
        return "FONT";
    case AssetType::LANG:
        return "LANG";
    case AssetType::DATA:
        return "DATA";
    case AssetType::ANIMATION:
        return "ANIMATION";
    case AssetType::PALETTE:
        return "PALETTE";
    case AssetType::ITEM:
        return "ITEM";
    default:
        return "ERROR";
    }
}

// Devuelve la lista de recursos de un tipo
std::vector<std::string> Asset::getListByType(AssetType type) const
{
    std::vector<std::string> list;

    for (auto f : file_list_)
    {
        if (f.type == type)
        {
            list.push_back(f.file);
        }
    }

    return list;
}