#pragma once

#include <SDL3/SDL.h>  // Para SDL_FPoint

#include <functional>  // Para function
#include <memory>      // Para shared_ptr

#include "core/rendering/sprite/moving_sprite.hpp"  // Para MovingSprite

class Texture;

// --- Estados de la tarjeta ---
enum class CardState {
    IDLE,      // No activada todavía
    ENTERING,  // Animación de entrada (zoom + rotación + desplazamiento con rebote)
    LANDED,    // En reposo sobre la mesa
    EXITING,   // Saliendo de pantalla girando
    FINISHED,  // Fuera de pantalla
};

// --- Clase CardSprite: tarjeta animada con zoom, rotación y sombra integrada ---
//
// Simula una tarjeta lanzada sobre una mesa desde un borde de la pantalla.
// Durante la entrada, interpola posición, zoom y rotación con easing (rebote).
// Durante la salida, se desplaza fuera de pantalla girando, sin sombra.
class CardSprite : public MovingSprite {
   public:
    explicit CardSprite(std::shared_ptr<Texture> texture);
    ~CardSprite() override = default;

    // --- Ciclo principal ---
    void update(float delta_time) override;
    void render() override;

    // --- Control de estado ---
    auto enable() -> bool;  // Inicia la animación de entrada (true si se activó)
    void startExit();       // Inicia la animación de salida

    // --- Consultas de estado ---
    [[nodiscard]] auto hasLanded() const -> bool;      // ¿Ha aterrizado definitivamente?
    [[nodiscard]] auto hasFirstTouch() const -> bool;  // ¿Ha tocado la mesa por primera vez? (primer rebote)
    [[nodiscard]] auto hasFinished() const -> bool;    // ¿Ha terminado completamente?
    [[nodiscard]] auto isExiting() const -> bool;      // ¿Está saliendo de pantalla?
    [[nodiscard]] auto getState() const -> CardState;  // Estado actual

    // --- Configuración de entrada ---
    void setEntryParams(float start_zoom, double start_angle, float duration_s, std::function<double(double)> easing);
    void setEntryPosition(float start_x, float start_y);  // Posición inicial (borde de pantalla)
    void setLandingPosition(float x, float y);            // Posición final centrada

    // --- Configuración de salida ---
    void setExitParams(float vx, float vy, float ax, float ay, double rotate_amount);
    void setExitLift(float target_zoom, float zoom_speed);  // Ganar altura al salir (zoom > 1.0)

    // --- Sombra ---
    void setShadowTexture(std::shared_ptr<Texture> texture);
    void setShadowOffset(float offset_x, float offset_y);

    // --- Limites de pantalla (para detectar salida) ---
    void setScreenBounds(float width, float height);

   private:
    // --- Estado ---
    CardState state_ = CardState::IDLE;
    bool first_touch_ = false;  // Primer contacto con la mesa (eased >= umbral)

    // --- Umbral para detectar el primer toque ---
    static constexpr double FIRST_TOUCH_THRESHOLD = 0.98;

    // --- Parámetros de entrada ---
    float start_zoom_ = 1.8F;
    double start_angle_ = 15.0;
    float entry_duration_s_ = 1.5F;
    float entry_elapsed_ = 0.0F;
    std::function<double(double)> entry_easing_;
    float entry_start_x_ = 0.0F;  // Posición inicial X (borde)
    float entry_start_y_ = 0.0F;  // Posición inicial Y (borde)
    float landing_x_ = 0.0F;
    float landing_y_ = 0.0F;

    // --- Parámetros de salida ---
    float exit_vx_ = 0.0F;
    float exit_vy_ = 0.0F;
    float exit_ax_ = 0.0F;
    float exit_ay_ = 0.0F;
    double exit_rotate_amount_ = 0.0;
    float exit_target_zoom_ = 1.0F;  // Zoom objetivo al salir (>1.0 = se eleva)
    float exit_zoom_speed_ = 0.0F;   // Velocidad de cambio de zoom por segundo

    // --- Sombra ---
    std::shared_ptr<Texture> shadow_texture_;
    float shadow_offset_x_ = 8.0F;
    float shadow_offset_y_ = 8.0F;
    bool shadow_visible_ = true;

    // --- Límites de pantalla ---
    float screen_width_ = 320.0F;
    float screen_height_ = 240.0F;

    // --- Constantes ---
    static constexpr float OFF_SCREEN_MARGIN = 50.0F;          // Margen fuera de pantalla para considerar FINISHED
    static constexpr float SHADOW_HEIGHT_MULTIPLIER = 400.0F;  // Pixels de separación de sombra por unidad de altura

    // --- Métodos internos ---
    void updateEntering(float delta_time);
    void updateExiting(float delta_time);
    void renderShadow();
    [[nodiscard]] auto isOffScreen() const -> bool;
};
