// init_hud_animator.cpp - Implementación de la animación inicial del HUD

#include "game/systems/init_hud_animator.hpp"

#include <SDL3/SDL.h>

#include <algorithm>
#include <cstdint>
#include <string>

#include "core/defaults.hpp"
#include "core/math/easing.hpp"
#include "core/rendering/line_renderer.hpp"

namespace Systems::InitHud {

auto computeRangeProgress(float global_progress,
                          float ratio_init,
                          float ratio_end) -> float {
    if (ratio_init >= ratio_end) {
        return (global_progress >= ratio_end) ? 1.0F : 0.0F;
    }
    if (global_progress < ratio_init) {
        return 0.0F;
    }
    if (global_progress > ratio_end) {
        return 1.0F;
    }
    return (global_progress - ratio_init) / (ratio_end - ratio_init);
}

auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
    const float EASED = Easing::ease_out_quad(progress);
    const SDL_FRect& ZONA = Defaults::Zones::PLAYAREA;
    // Y inicial: 50 px bajo la zona de juego.
    const float Y_INI = ZONA.y + ZONA.h + 50.0F;
    const float Y_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED);
    return Vec2{.x = final_position.x, .y = Y_ANIM};
}

void drawBordersAnimated(Rendering::Renderer* renderer, float progress) {
    const SDL_FRect& ZONA = Defaults::Zones::PLAYAREA;
    const float EASED = Easing::ease_out_quad(progress);

    const int X1 = static_cast<int>(ZONA.x);
    const int Y1 = static_cast<int>(ZONA.y);
    const int X2 = static_cast<int>(ZONA.x + ZONA.w);
    const int Y2 = static_cast<int>(ZONA.y + ZONA.h);
    const int CX = (X1 + X2) / 2;

    constexpr float PHASE_1_END = 0.33F;
    constexpr float PHASE_2_END = 0.66F;

    // Fase 1: línea superior crece desde el centro hacia los lados.
    if (EASED > 0.0F) {
        const float P = std::min(EASED / PHASE_1_END, 1.0F);
        const int X_LEFT = static_cast<int>(CX - ((CX - X1) * P));
        const int X_RIGHT = static_cast<int>(CX + ((X2 - CX) * P));
        Rendering::linea(renderer, CX, Y1, X_LEFT, Y1);
        Rendering::linea(renderer, CX, Y1, X_RIGHT, Y1);
    }

    // Fase 2: laterales bajan.
    if (EASED > PHASE_1_END) {
        const float P = std::min((EASED - PHASE_1_END) / (PHASE_2_END - PHASE_1_END), 1.0F);
        const int Y_BOTTOM = static_cast<int>(Y1 + ((Y2 - Y1) * P));
        Rendering::linea(renderer, X1, Y1, X1, Y_BOTTOM);
        Rendering::linea(renderer, X2, Y1, X2, Y_BOTTOM);
    }

    // Fase 3: línea inferior crece desde los lados hacia el centro.
    if (EASED > PHASE_2_END) {
        const float P = (EASED - PHASE_2_END) / (1.0F - PHASE_2_END);
        const int X_LEFT = static_cast<int>(X1 + ((CX - X1) * P));
        const int X_RIGHT = static_cast<int>(X2 - ((X2 - CX) * P));
        Rendering::linea(renderer, X1, Y2, X_LEFT, Y2);
        Rendering::linea(renderer, X2, Y2, X_RIGHT, Y2);
    }
}

void drawScoreboardAnimated(Graphics::VectorText& text,
                            const std::string& scoreboard_text,
                            float progress) {
    const float EASED = Easing::ease_out_quad(progress);

    constexpr float SCALE = 0.85F;
    constexpr float SPACING = 0.0F;
    const SDL_FRect& SCOREBOARD = Defaults::Zones::SCOREBOARD;
    const float CENTRE_X = SCOREBOARD.w / 2.0F;
    const float Y_FINAL = SCOREBOARD.y + (SCOREBOARD.h / 2.0F);
    // Posición inicial: fuera de la pantalla por debajo.
    const auto Y_INI = static_cast<float>(Defaults::Game::HEIGHT);
    const float Y_ANIM = Y_INI + ((Y_FINAL - Y_INI) * EASED);

    text.renderCentered(scoreboard_text,
                        Vec2{.x = CENTRE_X, .y = Y_ANIM},
                        SCALE, SPACING);
}

}  // namespace Systems::InitHud
