#pragma once

#include <SDL3/SDL.h>

#include <array>
#include <cstddef>
#include <memory>
#include <string>
#include <vector>

#include "game/ui/service_menu.hpp"
#include "utils/color.hpp"

class MenuOption;
class Text;

class MenuRenderer {
   public:
    // --- Nuevo: Enum para el modo de posicionamiento ---
    enum class PositionMode {
        CENTERED,  // La ventana se centra en el punto especificado
        FIXED      // La esquina superior izquierda coincide con el punto
    };

    MenuRenderer(const ServiceMenu* menu_state, std::shared_ptr<Text> element_text, std::shared_ptr<Text> title_text);

    // --- Métodos principales de la vista ---
    void render(const ServiceMenu* menu_state);
    void update(const ServiceMenu* menu_state, float delta_time);

    // --- Nuevos: Métodos de control de visibilidad y animación ---
    void show(const ServiceMenu* menu_state);
    void hide();
    [[nodiscard]] auto isVisible() const -> bool { return visible_; }
    [[nodiscard]] auto isFullyVisible() const -> bool { return visible_ && !show_hide_animation_.active && !resize_animation_.active; }
    [[nodiscard]] auto isAnimating() const -> bool { return resize_animation_.active || show_hide_animation_.active; }

    // --- Nuevos: Métodos de configuración de posición ---
    void setPosition(float x, float y, PositionMode mode);

    // Método para notificar al renderer que el layout puede haber cambiado
    void onLayoutChanged(const ServiceMenu* menu_state);
    void setLayout(const ServiceMenu* menu_state);

    // Animación de intercambio de valores entre dos filas del menú actual
    void startSwapAnimation(size_t idx_a, size_t idx_b);

    // Getters
    [[nodiscard]] auto getRect() const -> const SDL_FRect& { return rect_; }

   private:
    // --- Referencias a los renderizadores de texto ---
    std::shared_ptr<Text> element_text_;
    std::shared_ptr<Text> title_text_;

    // --- Variables de estado de la vista (layout y animación) ---
    SDL_FRect rect_{};
    SDL_FRect border_rect_{};
    size_t width_ = 0;
    size_t height_ = 0;
    size_t options_height_ = 0;
    size_t options_padding_ = 0;
    size_t options_y_ = 0;
    size_t title_height_ = 0;
    size_t title_padding_ = 0;
    size_t upper_height_ = 0;
    size_t lower_height_ = 0;
    size_t lower_padding_ = 0;
    size_t subtitle_offset_ = 0;  // Altura reservada para subtítulo del grupo actual
    Uint32 color_counter_ = 0;
    bool visible_ = false;

    // --- Posicionamiento ---
    PositionMode position_mode_ = PositionMode::CENTERED;
    float anchor_x_ = 0.0F;
    float anchor_y_ = 0.0F;

    // --- Límites de tamaño máximo ---
    size_t max_menu_width_ = 0;
    size_t max_menu_height_ = 0;

    // --- Estructuras de Animación ---
    struct ResizeAnimation {
        bool active = false;
        float start_width, start_height;
        float target_width, target_height;
        float elapsed = 0.0F;
        float duration = 0.2F;

        void start(float from_w, float from_h, float to_w, float to_h);
        void stop();
    } resize_animation_;

    struct ShowHideAnimation {
        enum class Type { NONE,
            SHOWING,
            HIDING };
        Type type = Type::NONE;
        bool active = false;
        float target_width, target_height;
        float elapsed = 0.0F;
        float duration = 0.25F;

        void startShow(float to_w, float to_h);
        void startHide();
        void stop();
    } show_hide_animation_;

    // Animación de intercambio: interpola la Y del VALOR de dos filas
    // durante su intercambio. El caption se queda estático.
    struct SwapAnimation {
        bool active = false;
        size_t idx_a = 0;
        size_t idx_b = 0;
        float elapsed = 0.0F;
        float duration = 0.4F;
    } swap_animation_;

    // --- Anchos precalculados ---
    std::array<int, ServiceMenu::SETTINGS_GROUP_SIZE> group_menu_widths_ = {};

    // --- Métodos privados de la vista ---
    void initializeMaxSizes();
    void setAnchors(const ServiceMenu* menu_state);
    auto calculateNewRect(const ServiceMenu* menu_state) -> SDL_FRect;
    void resize(const ServiceMenu* menu_state);
    void setSize(const ServiceMenu* menu_state);

    // Altura extra ocupada por el subtítulo del grupo actual (versión + hash en SYSTEM)
    [[nodiscard]] auto getGroupSubtitleHeight(const ServiceMenu* menu_state) const -> size_t;
    [[nodiscard]] static auto groupHasSubtitle(ServiceMenu::SettingsGroup group) -> bool;

    void updateAnimations(float delta_time);
    void updateResizeAnimation(float delta_time);
    void updateShowHideAnimation(float delta_time);
    void updateSwapAnimation(float delta_time);
    void updatePosition();

    void precalculateMenuWidths(const std::vector<std::unique_ptr<MenuOption>>& all_options, const ServiceMenu* menu_state);  // NOLINT(readability-avoid-const-params-in-decls)
    [[nodiscard]] auto getMenuWidthForGroup(ServiceMenu::SettingsGroup group) const -> int;
    [[nodiscard]] auto getAnimatedSelectedColor() const -> Color;
    void updateColorCounter();
    auto setRect(SDL_FRect rect) -> SDL_FRect;
    [[nodiscard]] auto getTruncatedValueWidth(const std::string& value, int available_width) const -> int;
    [[nodiscard]] auto getTruncatedValue(const std::string& value, int available_width) const -> std::string;
    [[nodiscard]] static auto easeOut(float t) -> float;
    [[nodiscard]] auto shouldShowContent() const -> bool;
};