#pragma once

#include <SDL3/SDL_stdinc.h>  // for Uint64

#include <vector>  // for std::vector in DynamicThemeKeyframe/DynamicTheme

// Configuración de ventana y pantalla
constexpr char WINDOW_CAPTION[] = "© 2025 ViBe3 Physics — JailDesigner";

// Resolución por defecto (usada si no se especifica en CLI)
constexpr int DEFAULT_SCREEN_WIDTH = 1280;  // Ancho lógico por defecto (si no hay -w)
constexpr int DEFAULT_SCREEN_HEIGHT = 720;  // Alto lógico por defecto (si no hay -h)
constexpr int DEFAULT_WINDOW_ZOOM = 1;      // Zoom inicial de ventana (1x = sin zoom)

constexpr int WINDOW_DESKTOP_MARGIN = 10;     // Margen mínimo con bordes del escritorio
constexpr int WINDOW_DECORATION_HEIGHT = 30;  // Altura estimada de decoraciones del SO

// Configuración de escala de ventana por pasos (F1/F2)
constexpr float WINDOW_SCALE_STEP = 0.1f;  // Incremento/decremento por pulsación (10%)
constexpr float WINDOW_SCALE_MIN = 0.5f;   // Escala mínima (50% de la resolución base)

// Configuración de física
constexpr float GRAVITY_FORCE = 0.2f;  // Fuerza de gravedad (píxeles/frame²)

// Fuente de la interfaz
#define APP_FONT "data/fonts/Exo2-Regular.ttf"

// Configuración de interfaz
constexpr float THEME_TRANSITION_DURATION = 0.5f;  // Duración de transiciones LERP entre temas (segundos)

// Configuración de notificaciones (sistema Notifier)
constexpr int TEXT_ABSOLUTE_SIZE = 12;           // Tamaño fuente base en píxeles físicos (múltiplo de 12px, tamaño nativo de la fuente)
constexpr Uint64 NOTIFICATION_DURATION = 2000;   // Duración default de notificaciones (ms)
constexpr Uint64 NOTIFICATION_SLIDE_TIME = 300;  // Duración animación entrada (ms)
constexpr Uint64 NOTIFICATION_FADE_TIME = 200;   // Duración animación salida (ms)
constexpr float NOTIFICATION_BG_ALPHA = 0.7f;    // Opacidad fondo semitransparente (0.0-1.0)
constexpr int NOTIFICATION_PADDING = 10;         // Padding interno del fondo (píxeles físicos)
constexpr int NOTIFICATION_TOP_MARGIN = 20;      // Margen superior desde borde pantalla (píxeles físicos)
constexpr char KIOSK_NOTIFICATION_TEXT[] = "Modo kiosko";

// Configuración de pérdida aleatoria en rebotes
constexpr float BASE_BOUNCE_COEFFICIENT = 0.75f;    // Coeficiente base IGUAL para todas las pelotas
constexpr float BOUNCE_RANDOM_LOSS_PERCENT = 0.1f;  // 0-10% pérdida adicional aleatoria en cada rebote
constexpr float LATERAL_LOSS_PERCENT = 0.02f;       // ±2% pérdida lateral en rebotes

// Configuración de masa/peso individual por pelota
constexpr float GRAVITY_MASS_MIN = 0.7f;  // Factor mínimo de masa (pelota ligera - 70% gravedad)
constexpr float GRAVITY_MASS_MAX = 1.3f;  // Factor máximo de masa (pelota pesada - 130% gravedad)

// Configuración de velocidad lateral al cambiar gravedad (muy sutil)
constexpr float GRAVITY_CHANGE_LATERAL_MIN = 0.04f;  // Velocidad lateral mínima (2.4 px/s)
constexpr float GRAVITY_CHANGE_LATERAL_MAX = 0.08f;  // Velocidad lateral máxima (4.8 px/s)

// Configuración de spawn inicial de pelotas
constexpr float BALL_SPAWN_MARGIN = 0.15f;  // Margen lateral para spawn (0.25 = 25% a cada lado)

// Escenarios de número de pelotas (teclas 1-8)
constexpr int SCENE_BALLS_1 = 10;
constexpr int SCENE_BALLS_2 = 50;
constexpr int SCENE_BALLS_3 = 100;
constexpr int SCENE_BALLS_4 = 500;
constexpr int SCENE_BALLS_5 = 1000;
constexpr int SCENE_BALLS_6 = 5000;
constexpr int SCENE_BALLS_7 = 10000;
constexpr int SCENE_BALLS_8 = 50000;  // Máximo escenario estándar (tecla 8)

constexpr int SCENARIO_COUNT = 8;
constexpr int BALL_COUNT_SCENARIOS[SCENARIO_COUNT] = {
    SCENE_BALLS_1,
    SCENE_BALLS_2,
    SCENE_BALLS_3,
    SCENE_BALLS_4,
    SCENE_BALLS_5,
    SCENE_BALLS_6,
    SCENE_BALLS_7,
    SCENE_BALLS_8};

constexpr int BOIDS_MAX_BALLS = SCENE_BALLS_5;  // 1 000 bolas máximo en modo BOIDS
constexpr int DEMO_AUTO_MIN_SCENARIO = 2;       // mínimo 100 bolas
constexpr int DEMO_AUTO_MAX_SCENARIO = 7;       // máximo sin restricción hardware (ajustado por benchmark)
constexpr int LOGO_MIN_SCENARIO_IDX = 4;        // mínimo 1000 bolas (sustituye LOGO_MODE_MIN_BALLS)
constexpr int CUSTOM_SCENARIO_IDX = 8;          // Escenario custom opcional (tecla 9, --custom-balls)

// Estructura para representar colores RGB
struct Color {
        int r, g, b;  // Componentes rojo, verde, azul (0-255)
};

// Estructura de tema de colores estático
struct ThemeColors {
        const char* name_en;                           // Nombre en inglés (para debug)
        const char* name_es;                           // Nombre en español (para display)
        int text_color_r, text_color_g, text_color_b;  // Color del texto del tema
        float bg_top_r, bg_top_g, bg_top_b;
        float bg_bottom_r, bg_bottom_g, bg_bottom_b;
        std::vector<Color> ball_colors;
};

// Estructura para keyframe de tema dinámico
struct DynamicThemeKeyframe {
        // Fondo degradado
        float bg_top_r, bg_top_g, bg_top_b;
        float bg_bottom_r, bg_bottom_g, bg_bottom_b;

        // Color de fondo de notificaciones
        int notif_bg_r, notif_bg_g, notif_bg_b;

        // Colores de pelotas en este keyframe
        std::vector<Color> ball_colors;

        // Duración de transición HACIA este keyframe (segundos)
        // 0.0 = estado inicial (sin transición)
        float duration;
};

// NOTA: La clase DynamicTheme (tema dinámico animado) está definida en themes/dynamic_theme.h
// Esta estructura de datos es solo para definir keyframes que se pasan al constructor

// Enum para dirección de gravedad
enum class GravityDirection {
    DOWN,  // ↓ Gravedad hacia abajo (por defecto)
    UP,    // ↑ Gravedad hacia arriba
    LEFT,  // ← Gravedad hacia la izquierda
    RIGHT  // → Gravedad hacia la derecha
};

// Enum para temas de colores (seleccionables con teclado numérico y Shift+Numpad)
// Todos los temas usan ahora sistema dinámico de keyframes
enum class ColorTheme {
    SUNSET = 0,        // Naranjas, rojos, amarillos, rosas (estático: 1 keyframe)
    OCEAN = 1,         // Azules, turquesas, blancos (estático: 1 keyframe)
    NEON = 2,          // Cian, magenta, verde lima, amarillo vibrante (estático: 1 keyframe)
    FOREST = 3,        // Verdes, marrones, amarillos otoño (estático: 1 keyframe)
    RGB = 4,           // RGB puros y subdivisiones matemáticas - fondo blanco (estático: 1 keyframe)
    MONOCHROME = 5,    // Fondo negro degradado, sprites blancos monocromáticos (estático: 1 keyframe)
    LAVENDER = 6,      // Degradado violeta-azul, pelotas amarillo dorado (estático: 1 keyframe)
    CRIMSON = 7,       // Fondo negro-rojo, pelotas rojas uniformes (estático: 1 keyframe)
    EMERALD = 8,       // Fondo negro-verde, pelotas verdes uniformes (estático: 1 keyframe)
    SUNRISE = 9,       // Amanecer: Noche → Alba → Día (animado: 4 keyframes, 12s ciclo)
    OCEAN_WAVES = 10,  // Olas oceánicas: Azul oscuro ↔ Turquesa (animado: 3 keyframes, 8s ciclo)
    NEON_PULSE = 11,   // Pulso neón: Negro ↔ Neón vibrante (animado: 3 keyframes, 3s ping-pong)
    FIRE = 12,         // Fuego vivo: Brasas → Llamas → Inferno (animado: 4 keyframes, 10s ciclo)
    AURORA = 13,       // Aurora boreal: Verde → Violeta → Cian (animado: 4 keyframes, 14s ciclo)
    VOLCANIC = 14      // Erupción volcánica: Ceniza → Erupción → Lava (animado: 4 keyframes, 12s ciclo)
};

// Enum para tipo de figura 3D
enum class ShapeType {
    NONE,         // Sin figura (modo física pura)
    SPHERE,       // Esfera Fibonacci (antiguo RotoBall)
    CUBE,         // Cubo rotante
    HELIX,        // Espiral 3D
    TORUS,        // Toroide/donut
    LISSAJOUS,    // Malla ondeante
    CYLINDER,     // Cilindro rotante
    ICOSAHEDRON,  // Icosaedro D20
    ATOM,         // Átomo con órbitas
    PNG_SHAPE     // Forma cargada desde PNG 1-bit
};

// Enum para modo de simulación
enum class SimulationMode {
    PHYSICS,  // Modo física normal con gravedad
    SHAPE,    // Modo figura 3D (Shape polimórfico)
    BOIDS     // Modo enjambre (Boids - comportamiento emergente)
};

// Enum para modo de aplicación (mutuamente excluyentes)
enum class AppMode {
    SANDBOX,    // Control manual del usuario (modo sandbox)
    DEMO,       // Modo demo completo (auto-play)
    DEMO_LITE,  // Modo demo lite (solo física/figuras)
    LOGO        // Modo logo (easter egg)
};

// Enum para modo de escalado en fullscreen (F5)
enum class ScalingMode {
    INTEGER,    // Escalado entero con barras negras (mantiene aspecto + píxel perfecto)
    LETTERBOX,  // Zoom hasta llenar una dimensión (una barra desaparece)
    STRETCH     // Estirar para llenar pantalla completa (puede distorsionar aspecto)
};

// Configuración de RotoBall (esfera 3D rotante)
constexpr float ROTOBALL_RADIUS_FACTOR = 0.333f;   // Radio como proporción de altura de pantalla (80/240 ≈ 0.333)
constexpr float ROTOBALL_ROTATION_SPEED_Y = 1.5f;  // Velocidad rotación eje Y (rad/s)
constexpr float ROTOBALL_ROTATION_SPEED_X = 0.8f;  // Velocidad rotación eje X (rad/s)
constexpr int ROTOBALL_MIN_BRIGHTNESS = 50;        // Brillo mínimo (fondo, 0-255)
constexpr int ROTOBALL_MAX_BRIGHTNESS = 255;       // Brillo máximo (frente, 0-255)

// Física de atracción para figuras 3D (sistema de resorte)
// SHAPE: Figuras 3D normales (Q/W/E/R/T/Y/U/I/O) - Mayor pegajosidad
constexpr float SHAPE_SPRING_K = 800.0f;      // Rigidez alta (pelotas más "pegadas")
constexpr float SHAPE_DAMPING_BASE = 60.0f;   // Amortiguación alta (menos rebote)
constexpr float SHAPE_DAMPING_NEAR = 150.0f;  // Absorción muy rápida al llegar
constexpr float SHAPE_NEAR_THRESHOLD = 8.0f;  // Umbral "cerca" más amplio
constexpr float SHAPE_MAX_FORCE = 2000.0f;    // Permite fuerzas más fuertes

// Configuración del Cubo (cubo 3D rotante)
constexpr float CUBE_SIZE_FACTOR = 0.25f;      // Tamaño como proporción de altura (60/240 = 0.25)
constexpr float CUBE_ROTATION_SPEED_X = 0.5f;  // Velocidad rotación eje X (rad/s)
constexpr float CUBE_ROTATION_SPEED_Y = 0.7f;  // Velocidad rotación eje Y (rad/s)
constexpr float CUBE_ROTATION_SPEED_Z = 0.3f;  // Velocidad rotación eje Z (rad/s)

// Configuración de Helix (espiral helicoidal 3D)
constexpr float HELIX_RADIUS_FACTOR = 0.25f;    // Radio de la espiral (proporción de altura)
constexpr float HELIX_PITCH_FACTOR = 0.25f;     // Separación vertical entre vueltas (proporción de altura)
constexpr float HELIX_NUM_TURNS = 3.0f;         // Número de vueltas completas (1-5)
constexpr float HELIX_ROTATION_SPEED_Y = 1.2f;  // Velocidad rotación eje Y (rad/s)
constexpr float HELIX_PHASE_SPEED = 0.5f;       // Velocidad de animación vertical (rad/s)

// Configuración de Lissajous Curve 3D (curva paramétrica)
constexpr float LISSAJOUS_SIZE_FACTOR = 0.35f;      // Amplitud de la curva (proporción de altura)
constexpr float LISSAJOUS_FREQ_X = 3.0f;            // Frecuencia en eje X (ratio 3:2:1)
constexpr float LISSAJOUS_FREQ_Y = 2.0f;            // Frecuencia en eje Y
constexpr float LISSAJOUS_FREQ_Z = 1.0f;            // Frecuencia en eje Z
constexpr float LISSAJOUS_PHASE_SPEED = 1.0f;       // Velocidad de animación de fase (rad/s)
constexpr float LISSAJOUS_ROTATION_SPEED_X = 0.4f;  // Velocidad rotación global X (rad/s)
constexpr float LISSAJOUS_ROTATION_SPEED_Y = 0.6f;  // Velocidad rotación global Y (rad/s)

// Configuración de Torus (toroide/donut 3D)
constexpr float TORUS_MAJOR_RADIUS_FACTOR = 0.25f;  // Radio mayor R (centro torus a centro tubo)
constexpr float TORUS_MINOR_RADIUS_FACTOR = 0.12f;  // Radio menor r (grosor del tubo)
constexpr float TORUS_ROTATION_SPEED_X = 0.6f;      // Velocidad rotación eje X (rad/s)
constexpr float TORUS_ROTATION_SPEED_Y = 0.9f;      // Velocidad rotación eje Y (rad/s)
constexpr float TORUS_ROTATION_SPEED_Z = 0.3f;      // Velocidad rotación eje Z (rad/s)

// Configuración de Cylinder (cilindro 3D)
constexpr float CYLINDER_RADIUS_FACTOR = 0.25f;    // Radio del cilindro (proporción de altura)
constexpr float CYLINDER_HEIGHT_FACTOR = 0.5f;     // Altura del cilindro (proporción de altura)
constexpr float CYLINDER_ROTATION_SPEED_Y = 1.0f;  // Velocidad rotación eje Y (rad/s)

// Configuración de Icosahedron (icosaedro D20)
constexpr float ICOSAHEDRON_RADIUS_FACTOR = 0.30f;    // Radio de la esfera circunscrita
constexpr float ICOSAHEDRON_ROTATION_SPEED_X = 0.4f;  // Velocidad rotación eje X (rad/s)
constexpr float ICOSAHEDRON_ROTATION_SPEED_Y = 0.7f;  // Velocidad rotación eje Y (rad/s)
constexpr float ICOSAHEDRON_ROTATION_SPEED_Z = 0.2f;  // Velocidad rotación eje Z (rad/s)

// Configuración de Atom (núcleo con órbitas electrónicas)
constexpr float ATOM_NUCLEUS_RADIUS_FACTOR = 0.08f;  // Radio del núcleo central
constexpr float ATOM_ORBIT_RADIUS_FACTOR = 0.30f;    // Radio de las órbitas
constexpr float ATOM_NUM_ORBITS = 3;                 // Número de órbitas
constexpr float ATOM_ORBIT_ROTATION_SPEED = 2.0f;    // Velocidad de electrones (rad/s)
constexpr float ATOM_ROTATION_SPEED_Y = 0.5f;        // Velocidad rotación global (rad/s)

// Configuración de PNG Shape (forma desde imagen PNG 1-bit)
constexpr float PNG_SIZE_FACTOR = 0.8f;              // Tamaño como proporción de altura (80% pantalla)
constexpr float PNG_EXTRUSION_DEPTH_FACTOR = 0.12f;  // Profundidad de extrusión (compacta)
constexpr int PNG_NUM_EXTRUSION_LAYERS = 15;         // Capas de extrusión (más capas = más pegajosidad)
constexpr bool PNG_USE_EDGES_ONLY = false;           // true = solo bordes, false = relleno completo
// Rotación "legible" (texto de frente con volteretas ocasionales)
constexpr float PNG_IDLE_TIME_MIN = 0.5f;       // Tiempo mínimo de frente (segundos) - modo MANUAL
constexpr float PNG_IDLE_TIME_MAX = 2.0f;       // Tiempo máximo de frente (segundos) - modo MANUAL
constexpr float PNG_IDLE_TIME_MIN_LOGO = 2.0f;  // Tiempo mínimo de frente en LOGO MODE
constexpr float PNG_IDLE_TIME_MAX_LOGO = 4.0f;  // Tiempo máximo de frente en LOGO MODE
constexpr float PNG_FLIP_SPEED = 3.0f;          // Velocidad voltereta (rad/s)
constexpr float PNG_FLIP_DURATION = 1.5f;       // Duración voltereta (segundos)

// Control manual de escala de figuras 3D (Numpad +/-)
constexpr float SHAPE_SCALE_MIN = 0.3f;      // Escala mínima (30%)
constexpr float SHAPE_SCALE_MAX = 3.0f;      // Escala máxima (300%)
constexpr float SHAPE_SCALE_STEP = 0.1f;     // Incremento por pulsación
constexpr float SHAPE_SCALE_DEFAULT = 1.0f;  // Escala por defecto (100%)

// Configuración de Modo DEMO (auto-play completo)
constexpr float DEMO_ACTION_INTERVAL_MIN = 2.0f;  // Tiempo mínimo entre acciones (segundos)
constexpr float DEMO_ACTION_INTERVAL_MAX = 6.0f;  // Tiempo máximo entre acciones (segundos)

// Pesos de probabilidad DEMO MODE (valores relativos, se normalizan)
constexpr int DEMO_WEIGHT_GRAVITY_DIR = 12;       // Cambiar dirección gravedad (12%)
constexpr int DEMO_WEIGHT_GRAVITY_TOGGLE = 15;    // Toggle gravedad ON/OFF (15%) - ¡Ver caer pelotas!
constexpr int DEMO_WEIGHT_SHAPE = 22;             // Activar figura 3D (22%) - Construir figuras
constexpr int DEMO_WEIGHT_TOGGLE_PHYSICS = 18;    // Toggle física ↔ figura (18%) - ¡Destruir figuras!
constexpr int DEMO_WEIGHT_REGENERATE_SHAPE = 10;  // Re-generar misma figura (10%) - Reconstruir
constexpr int DEMO_WEIGHT_THEME = 12;             // Cambiar tema de colores (12%)
constexpr int DEMO_WEIGHT_SCENARIO = 2;           // Cambiar número de pelotas (2%) - MUY OCASIONAL
constexpr int DEMO_WEIGHT_IMPULSE = 6;            // Aplicar impulso (SPACE) (6%)
constexpr int DEMO_WEIGHT_DEPTH_ZOOM = 1;         // Toggle profundidad (1%)
constexpr int DEMO_WEIGHT_SHAPE_SCALE = 1;        // Cambiar escala figura (1%)
constexpr int DEMO_WEIGHT_SPRITE = 1;             // Cambiar sprite (1%)
// TOTAL: 100

// Configuración de Modo DEMO LITE (solo física/figuras)
constexpr float DEMO_LITE_ACTION_INTERVAL_MIN = 1.5f;  // Más rápido que demo completo
constexpr float DEMO_LITE_ACTION_INTERVAL_MAX = 4.0f;

// Pesos de probabilidad DEMO LITE (solo física/figuras, sin cambios de escenario/tema)
constexpr int DEMO_LITE_WEIGHT_GRAVITY_DIR = 25;     // Cambiar dirección gravedad (25%)
constexpr int DEMO_LITE_WEIGHT_GRAVITY_TOGGLE = 20;  // Toggle gravedad ON/OFF (20%)
constexpr int DEMO_LITE_WEIGHT_SHAPE = 25;           // Activar figura 3D (25%)
constexpr int DEMO_LITE_WEIGHT_TOGGLE_PHYSICS = 20;  // Toggle física ↔ figura (20%)
constexpr int DEMO_LITE_WEIGHT_IMPULSE = 10;         // Aplicar impulso (10%)
// TOTAL: 100

// Configuración de Modo LOGO (easter egg - "marca de agua")
constexpr float LOGO_MODE_SHAPE_SCALE = 1.2f;     // Escala de figura en modo logo (120%)
constexpr float LOGO_ACTION_INTERVAL_MIN = 3.0f;  // Tiempo mínimo entre alternancia SHAPE/PHYSICS (escalado con resolución)
constexpr float LOGO_ACTION_INTERVAL_MAX = 5.0f;  // Tiempo máximo entre alternancia SHAPE/PHYSICS (escalado con resolución)
constexpr int LOGO_WEIGHT_TOGGLE_PHYSICS = 100;   // Único peso: alternar SHAPE ↔ PHYSICS (100%)

// Sistema de convergencia para LOGO MODE (evita interrupciones prematuras en resoluciones altas)
constexpr float LOGO_CONVERGENCE_MIN = 0.75f;       // 75% mínimo (permite algo de movimiento al disparar)
constexpr float LOGO_CONVERGENCE_MAX = 1.00f;       // 100% máximo (completamente formado)
constexpr float LOGO_CONVERGENCE_DISTANCE = 20.0f;  // Distancia (px) para considerar pelota "convergida" (más permisivo que SHAPE_NEAR)

// Probabilidad de salto a Logo Mode desde DEMO/DEMO_LITE (%)
// Relación DEMO:LOGO = 6:1 (pasa 6x más tiempo en DEMO que en LOGO)
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO = 5;       // 5% probabilidad en DEMO normal (más raro)
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE = 3;  // 3% probabilidad en DEMO LITE (aún más raro)

// Sistema de espera de flips en LOGO MODE (camino alternativo de decisión)
constexpr int LOGO_FLIP_WAIT_MIN = 1;           // Mínimo de flips a esperar antes de cambiar a PHYSICS
constexpr int LOGO_FLIP_WAIT_MAX = 3;           // Máximo de flips a esperar
constexpr float LOGO_FLIP_TRIGGER_MIN = 0.20f;  // 20% mínimo de progreso de flip para trigger
constexpr float LOGO_FLIP_TRIGGER_MAX = 0.80f;  // 80% máximo de progreso de flip para trigger
constexpr int LOGO_FLIP_WAIT_PROBABILITY = 50;  // 50% probabilidad de elegir el camino "esperar flip"

// Configuración de AppLogo (logo periódico en pantalla)
constexpr float APPLOGO_DISPLAY_INTERVAL = 90.0f;   // Intervalo entre apariciones del logo (segundos)
constexpr float APPLOGO_DISPLAY_DURATION = 30.0f;   // Duración de visibilidad del logo (segundos)
constexpr float APPLOGO_ANIMATION_DURATION = 0.5f;  // Duración de animación entrada/salida (segundos)
constexpr float APPLOGO_HEIGHT_PERCENT = 0.4f;      // Altura del logo = 40% de la altura de pantalla
constexpr float APPLOGO_PADDING_PERCENT = 0.05f;    // Padding desde esquina inferior-derecha = 10%
constexpr float APPLOGO_LOGO2_DELAY = 0.25f;        // Retraso de Logo 2 respecto a Logo 1 (segundos)

// Configuración de Modo BOIDS (comportamiento de enjambre)
// TIME-BASED CONVERSION (frame-based → time-based):
// - Radios: sin cambios (píxeles)
// - Velocidades (MAX_SPEED, MIN_SPEED): ×60 (px/frame → px/s)
// - Aceleraciones puras (SEPARATION, COHESION): ×60² = ×3600 (px/frame² → px/s²)
// - Steering proporcional (ALIGNMENT): ×60 (proporcional a velocidad)
// - Límite velocidad (MAX_FORCE): ×60 (px/frame → px/s)
constexpr float BOID_SEPARATION_RADIUS = 30.0f;    // Radio para evitar colisiones (píxeles)
constexpr float BOID_ALIGNMENT_RADIUS = 50.0f;     // Radio para alinear velocidad con vecinos
constexpr float BOID_COHESION_RADIUS = 80.0f;      // Radio para moverse hacia centro del grupo
constexpr float BOID_SEPARATION_WEIGHT = 5400.0f;  // Aceleración de separación (px/s²) [era 1.5 × 3600]
constexpr float BOID_ALIGNMENT_WEIGHT = 60.0f;     // Steering de alineación (proporcional) [era 1.0 × 60]
constexpr float BOID_COHESION_WEIGHT = 3.6f;       // Aceleración de cohesión (px/s²) [era 0.001 × 3600]
constexpr float BOID_MAX_SPEED = 150.0f;           // Velocidad máxima (px/s) [era 2.5 × 60]
constexpr float BOID_MAX_FORCE = 3.0f;             // Fuerza máxima de steering (px/s) [era 0.05 × 60]
constexpr float BOID_MIN_SPEED = 18.0f;            // Velocidad mínima (px/s) [era 0.3 × 60]
constexpr float BOID_BOUNDARY_MARGIN = 50.0f;      // Distancia a borde para activar repulsión (píxeles)
constexpr float BOID_BOUNDARY_WEIGHT = 7200.0f;    // Aceleración de repulsión de bordes (px/s²) [más fuerte que separation]

// FASE 2: Spatial Hash Grid para optimización O(n²) → O(n)
constexpr float BOID_GRID_CELL_SIZE = 100.0f;  // Tamaño de celda del grid (píxeles)
                                               // Debe ser ≥ BOID_COHESION_RADIUS para funcionar correctamente

constexpr float PI = 3.14159265358979323846f;  // Constante PI

// Función auxiliar para obtener la ruta del directorio del ejecutable
#include <filesystem>
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <limits.h>
#include <mach-o/dyld.h>
#else
#include <limits.h>
#include <unistd.h>
#endif

inline std::string getExecutableDirectory() {
#ifdef _WIN32
    char buffer[MAX_PATH];
    GetModuleFileNameA(NULL, buffer, MAX_PATH);
    std::filesystem::path exe_path(buffer);
    return exe_path.parent_path().string();
#elif defined(__APPLE__)
    char buffer[PATH_MAX];
    uint32_t size = sizeof(buffer);
    if (_NSGetExecutablePath(buffer, &size) == 0) {
        std::filesystem::path exe_path(buffer);
        return exe_path.parent_path().string();
    }
    return ".";
#else
    // Linux y otros Unix
    char buffer[PATH_MAX];
    ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
    if (len != -1) {
        buffer[len] = '\0';
        std::filesystem::path exe_path(buffer);
        return exe_path.parent_path().string();
    }
    return ".";
#endif
}

// Función auxiliar para obtener la ruta del directorio de recursos
inline std::string getResourcesDirectory() {
    std::string exe_dir = getExecutableDirectory();

#ifdef MACOS_BUNDLE
    // En macOS Bundle: ejecutable está en Contents/MacOS/, recursos en Contents/Resources/
    std::filesystem::path resources_path = std::filesystem::path(exe_dir) / ".." / "Resources";
    return resources_path.string();
#else
    // En desarrollo o releases normales: recursos están junto al ejecutable
    return exe_dir;
#endif
}