#pragma once

#include <SDL3/SDL_rect.h>  // for SDL_FRect

#include <memory>  // for shared_ptr, unique_ptr

#include "defines.hpp"          // for Color
#include "external/sprite.hpp"  // for Sprite
class Texture;

class Ball {
    private:
        std::unique_ptr<Sprite> sprite_;  // Sprite para pintar la clase
        SDL_FRect pos_;                   // Posición y tamaño de la pelota
        float vx_, vy_;                   // Velocidad
        float gravity_force_;             // Gravedad base
        float gravity_mass_factor_;       // Factor de masa individual (0.7-1.3, afecta gravedad)
        GravityDirection gravity_direction_; // Direcci\u00f3n de la gravedad
        int screen_width_;                // Ancho del terreno de juego
        int screen_height_;               // Alto del terreno de juego
        Color color_;                     // Color de la pelota
        bool on_surface_;                 // Indica si la pelota est\u00e1 en la superficie (suelo/techo/pared)
        float loss_;                      // Coeficiente de rebote. Pérdida de energía en cada rebote

        // Datos para modo Shape (figuras 3D)
        float pos_3d_x_, pos_3d_y_, pos_3d_z_;  // Posición 3D en la figura
        float target_x_, target_y_;              // Posición destino 2D (proyección)
        float depth_brightness_;                 // Brillo según profundidad Z (0.0-1.0)
        float depth_scale_;                      // Escala según profundidad Z (0.5-1.5)
        bool shape_attraction_active_;           // ¿Está siendo atraída hacia la figura?

    public:
        // Constructor
        Ball(float x, float y, float vx, float vy, Color color, std::shared_ptr<Texture> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir = GravityDirection::DOWN, float mass_factor = 1.0f);

        // Destructor
        ~Ball() = default;

        // Actualiza la lógica de la clase
        void update(float deltaTime);

        // Pinta la clase
        void render();

        // Modifica la velocidad
        void modVel(float vx, float vy);

        // Cambia la gravedad
        void switchGravity();

        // Reactiva la gravedad si está desactivada
        void enableGravityIfDisabled();

        // Fuerza gravedad ON (siempre activa)
        void forceGravityOn();

        // Fuerza gravedad OFF (siempre desactiva)
        void forceGravityOff();

        // Cambia la direcci\u00f3n de gravedad
        void setGravityDirection(GravityDirection direction);

        // Aplica un peque\u00f1o empuje lateral aleatorio
        void applyRandomLateralPush();

        // Getters para debug
        float getVelocityY() const { return vy_; }
        float getVelocityX() const { return vx_; }
        float getGravityForce() const { return gravity_force_; }
        float getLossCoefficient() const { return loss_; }
        GravityDirection getGravityDirection() const { return gravity_direction_; }
        bool isOnSurface() const { return on_surface_; }

        // Getters/Setters para velocidad (usado por BoidManager)
        void getVelocity(float& vx, float& vy) const { vx = vx_; vy = vy_; }
        void setVelocity(float vx, float vy) { vx_ = vx; vy_ = vy; }

        // Setter para posición simple (usado por BoidManager)
        void setPosition(float x, float y) { pos_.x = x; pos_.y = y; }

        // Getters/Setters para batch rendering
        SDL_FRect getPosition() const { return pos_; }
        Color getColor() const { return color_; }
        void setColor(const Color& color) { color_ = color; }

        // Sistema de cambio de sprite dinámico
        void updateSize(int new_size);  // Actualizar tamaño de hitbox
        void setTexture(std::shared_ptr<Texture> texture);  // Cambiar textura del sprite

        // Funciones para modo Shape (figuras 3D)
        void setShapePosition3D(float x, float y, float z);
        void setShapeTarget2D(float x, float y);
        void setShapeScreenPosition(float x, float y);  // Establecer posición directa en pantalla
        void setDepthBrightness(float brightness);
        float getDepthBrightness() const { return depth_brightness_; }
        void setDepthScale(float scale);
        float getDepthScale() const { return depth_scale_; }

        // Sistema de atracción física hacia figuras 3D
        void enableShapeAttraction(bool enable);
        float getDistanceToTarget() const;  // Distancia actual al punto objetivo
        void applyShapeForce(float target_x, float target_y, float sphere_radius, float deltaTime,
                            float spring_k = SHAPE_SPRING_K,
                            float damping_base = SHAPE_DAMPING_BASE,
                            float damping_near = SHAPE_DAMPING_NEAR,
                            float near_threshold = SHAPE_NEAR_THRESHOLD,
                            float max_force = SHAPE_MAX_FORCE);
};