#include "app/TextureLoader.h"

#include <SDL3_image/SDL_image.h>

#include <algorithm>
#include <mutex>
#include <sstream>

#include "utils/ImagePathResolver.h"

TextureLoader::TextureLoader(
    std::atomic<int>& loadedTasks,
    std::string& currentLoadingFile,
    std::mutex& currentLoadingMutex,
    std::vector<std::string>& assetLoadErrors,
    std::mutex& assetLoadErrorsMutex)
    : loadedTasks_(loadedTasks)
    , currentLoadingFile_(currentLoadingFile)
    , currentLoadingMutex_(currentLoadingMutex)
    , assetLoadErrors_(assetLoadErrors)
    , assetLoadErrorsMutex_(assetLoadErrorsMutex)
{
}

void TextureLoader::setCurrentLoadingFile(const std::string& filename) {
    std::lock_guard<std::mutex> lk(currentLoadingMutex_);
    currentLoadingFile_ = filename;
}

void TextureLoader::clearCurrentLoadingFile() {
    std::lock_guard<std::mutex> lk(currentLoadingMutex_);
    currentLoadingFile_.clear();
}

void TextureLoader::recordAssetLoadError(const std::string& message) {
    std::lock_guard<std::mutex> lk(assetLoadErrorsMutex_);
    assetLoadErrors_.emplace_back(message);
}

SDL_Texture* TextureLoader::loadFromImage(SDL_Renderer* renderer, const std::string& path, int* outW, int* outH) {
    if (!renderer) {
        return nullptr;
    }

    const std::string resolvedPath = AssetPath::resolveImagePath(path);
    setCurrentLoadingFile(resolvedPath.empty() ? path : resolvedPath);

    SDL_Surface* surface = IMG_Load(resolvedPath.c_str());
    if (!surface) {
        {
            std::ostringstream ss;
            ss << "Image load failed: " << path << " (" << resolvedPath << "): " << SDL_GetError();
            recordAssetLoadError(ss.str());
        }
        loadedTasks_.fetch_add(1);
        clearCurrentLoadingFile();
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load image %s (resolved: %s): %s", path.c_str(), resolvedPath.c_str(), SDL_GetError());
        return nullptr;
    }

    if (outW) {
        *outW = surface->w;
    }
    if (outH) {
        *outH = surface->h;
    }

    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_DestroySurface(surface);

    if (!texture) {
        {
            std::ostringstream ss;
            ss << "Texture create failed: " << resolvedPath << ": " << SDL_GetError();
            recordAssetLoadError(ss.str());
        }
        loadedTasks_.fetch_add(1);
        clearCurrentLoadingFile();
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create texture from %s: %s", resolvedPath.c_str(), SDL_GetError());
        return nullptr;
    }

    loadedTasks_.fetch_add(1);
    clearCurrentLoadingFile();

    if (resolvedPath != path) {
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded %s via %s", path.c_str(), resolvedPath.c_str());
    }

    return texture;
}
