#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[] = "ViBe3 Physics (JailDesigner 2025)";

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

// Configuración de zoom dinámico de ventana
constexpr int WINDOW_ZOOM_MIN = 1;            // Zoom mínimo (320x240)
constexpr int WINDOW_ZOOM_MAX = 10;           // Zoom máximo teórico (3200x2400)
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 física
constexpr float GRAVITY_FORCE = 0.2f;  // Fuerza de gravedad (píxeles/frame²)

// Configuración de interfaz
constexpr Uint64 TEXT_DURATION = 2000;  // Duración del texto informativo (ms)

// 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 BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50000};

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

// 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;

        // 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;
};

// Estructura para tema dinámico (animado)
struct DynamicTheme {
        const char* name_en;                           // Nombre en inglés
        const char* name_es;                           // Nombre en español
        int text_color_r, text_color_g, text_color_b;  // Color del texto del tema
        std::vector<DynamicThemeKeyframe> keyframes;   // Mínimo 2 keyframes
        bool loop;                                     // ¿Volver al inicio al terminar?
};

// 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)
// 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)
    SUNRISE = 7,      // Amanecer: Noche → Alba → Día (animado: 4 keyframes, 12s ciclo)
    OCEAN_WAVES = 8,  // Olas oceánicas: Azul oscuro ↔ Turquesa (animado: 3 keyframes, 8s ciclo)
    NEON_PULSE = 9    // Pulso neón: Negro ↔ Neón vibrante (animado: 3 keyframes, 3s ping-pong)
};

// 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
    WAVE_GRID,    // 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)
};

// 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 float ROTOBALL_TRANSITION_TIME = 1.5f;   // Tiempo de transición (segundos)
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 Wave Grid (malla ondeante 3D)
constexpr float WAVE_GRID_SIZE_FACTOR = 0.35f;      // Tamaño del grid (proporción de altura)
constexpr float WAVE_GRID_AMPLITUDE = 0.15f;        // Amplitud de las ondas (proporción de altura)
constexpr float WAVE_GRID_FREQUENCY = 3.0f;         // Frecuencia de ondas (ciclos por grid)
constexpr float WAVE_GRID_PHASE_SPEED = 2.0f;       // Velocidad de animación de ondas (rad/s)
constexpr float WAVE_GRID_ROTATION_SPEED_Y = 0.4f;  // Velocidad rotación eje 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 = 3.0f;  // Tiempo mínimo de frente en LOGO MODE
constexpr float PNG_IDLE_TIME_MAX_LOGO = 5.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 int LOGO_MODE_MIN_BALLS = 500;              // Mínimo de pelotas para activar modo logo
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)

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 <mach-o/dyld.h>
#include <limits.h>
#else
#include <unistd.h>
#include <limits.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
}