#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "logo_scaler.hpp"

#include <SDL3/SDL_error.h>    // Para SDL_GetError
#include <SDL3/SDL_log.h>      // Para SDL_Log
#include <SDL3/SDL_pixels.h>   // Para SDL_PixelFormat
#include <SDL3/SDL_render.h>   // Para SDL_CreateTexture
#include <SDL3/SDL_surface.h>  // Para SDL_CreateSurfaceFrom
#include <SDL3/SDL_video.h>    // Para SDL_GetDisplays

#include <cstdlib>   // Para free()
#include <iostream>  // Para std::cout

#include "external/stb_image.h"          // Para stbi_load, stbi_image_free
#include "external/stb_image_resize2.h"  // Para stbir_resize_uint8_srgb
#include "resource_manager.hpp"          // Para cargar desde pack

// ============================================================================
// Detectar resolución nativa del monitor principal
// ============================================================================

auto LogoScaler::detectNativeResolution(int& native_width, int& native_height) -> bool {
    int num_displays = 0;
    SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);

    if (displays == nullptr || num_displays == 0) {
        SDL_Log("Error al obtener displays: %s", SDL_GetError());
        return false;
    }

    // Obtener resolución del display principal (displays[0])
    const auto* dm = SDL_GetCurrentDisplayMode(displays[0]);
    if (dm == nullptr) {
        SDL_Log("Error al obtener modo del display: %s", SDL_GetError());
        SDL_free(displays);
        return false;
    }

    native_width = dm->w;
    native_height = dm->h;

    SDL_free(displays);

    return true;
}

// ============================================================================
// Cargar PNG y escalar al tamaño especificado
// ============================================================================

auto LogoScaler::loadAndScale(const std::string& path,
    int target_width,
    int target_height,
    int& out_width,
    int& out_height) -> unsigned char* {
    // 1. Intentar cargar imagen desde ResourceManager (pack o disco)
    int orig_width;
    int orig_height;
    int orig_channels;
    unsigned char* orig_data = nullptr;

    // 1a. Cargar desde ResourceManager
    unsigned char* resource_data = nullptr;
    size_t resource_size = 0;

    if (ResourceManager::loadResource(path, resource_data, resource_size)) {
        // Descodificar imagen desde memoria usando stb_image
        orig_data = stbi_load_from_memory(resource_data, static_cast<int>(resource_size), &orig_width, &orig_height, &orig_channels, STBI_rgb_alpha);
        delete[] resource_data;  // Liberar buffer temporal
    }

    // 1b. Si falla todo, error
    if (orig_data == nullptr) {
        SDL_Log("Error al cargar imagen %s: %s", path.c_str(), stbi_failure_reason());
        return nullptr;
    }

    // 2. Calcular tamaño final manteniendo aspect ratio
    // El alto está fijado por target_height (APPLOGO_HEIGHT_PERCENT)
    // Calcular ancho proporcional al aspect ratio original
    float aspect_ratio = static_cast<float>(orig_width) / static_cast<float>(orig_height);
    out_width = static_cast<int>(target_height * aspect_ratio);
    out_height = target_height;

    // 3. Alocar buffer para imagen escalada (RGBA = 4 bytes por píxel)
    auto* scaled_data = static_cast<unsigned char*>(malloc(out_width * out_height * 4));
    if (scaled_data == nullptr) {
        SDL_Log("Error al alocar memoria para imagen escalada");
        stbi_image_free(orig_data);
        return nullptr;
    }

    // 4. Escalar con stb_image_resize2 (algoritmo Mitchell, espacio sRGB)
    // La función devuelve el puntero de salida, o nullptr si falla
    unsigned char* result = stbir_resize_uint8_srgb(
        orig_data,
        orig_width,
        orig_height,
        0,  // Input
        scaled_data,
        out_width,
        out_height,
        0,          // Output
        STBIR_RGBA  // Formato píxel
    );

    // Liberar imagen original (ya no la necesitamos)
    stbi_image_free(orig_data);

    if (result == nullptr) {
        SDL_Log("Error al escalar imagen");
        free(scaled_data);
        return nullptr;
    }

    return scaled_data;
}

// ============================================================================
// Crear textura SDL desde buffer RGBA
// ============================================================================

auto LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
    unsigned char* data,
    int width,
    int height) -> SDL_Texture* {
    if (renderer == nullptr || data == nullptr || width <= 0 || height <= 0) {
        SDL_Log("Parámetros inválidos para createTextureFromBuffer");
        return nullptr;
    }

    // 1. Crear surface SDL desde buffer RGBA
    int pitch = width * 4;  // 4 bytes por píxel (RGBA)
    SDL_PixelFormat pixel_format = SDL_PIXELFORMAT_RGBA32;

    SDL_Surface* surface = SDL_CreateSurfaceFrom(
        width,
        height,
        pixel_format,
        data,
        pitch);

    if (surface == nullptr) {
        SDL_Log("Error al crear surface: %s", SDL_GetError());
        return nullptr;
    }

    // 2. Crear textura desde surface
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

    if (texture == nullptr) {
        SDL_Log("Error al crear textura: %s", SDL_GetError());
        SDL_DestroySurface(surface);
        return nullptr;
    }

    // 3. Liberar surface (la textura ya tiene los datos)
    SDL_DestroySurface(surface);

    return texture;
}
