#include "lissajous_shape.hpp"
#include "defines.hpp"
#include <cmath>

void LissajousShape::generatePoints(int num_points, float screen_width, float screen_height) {
    num_points_ = num_points;
    amplitude_ = screen_height * LISSAJOUS_SIZE_FACTOR;

    // Inicializar frecuencias desde defines.h
    freq_x_ = LISSAJOUS_FREQ_X;
    freq_y_ = LISSAJOUS_FREQ_Y;
    freq_z_ = LISSAJOUS_FREQ_Z;
}

void LissajousShape::update(float delta_time, float screen_width, float screen_height) {
    // Recalcular amplitud por si cambió resolución (F4)
    amplitude_ = screen_height * LISSAJOUS_SIZE_FACTOR;

    // Actualizar rotación global
    rotation_x_ += LISSAJOUS_ROTATION_SPEED_X * delta_time;
    rotation_y_ += LISSAJOUS_ROTATION_SPEED_Y * delta_time;

    // Actualizar fase para animación (morphing de la curva)
    phase_x_ += LISSAJOUS_PHASE_SPEED * delta_time;
    phase_z_ += LISSAJOUS_PHASE_SPEED * delta_time * 0.7f;  // Z rota más lento para variación
}

void LissajousShape::getPoint3D(int index, float& x, float& y, float& z) const {
    // Mapear índice [0, num_points-1] a parámetro t [0, 2π]
    float t = (static_cast<float>(index) / static_cast<float>(num_points_)) * 2.0f * PI;

    // Ecuaciones de Lissajous 3D
    // x(t) = A * sin(freq_x * t + phase_x)
    // y(t) = A * sin(freq_y * t)
    // z(t) = A * sin(freq_z * t + phase_z)
    float x_local = amplitude_ * sinf(freq_x_ * t + phase_x_);
    float y_local = amplitude_ * sinf(freq_y_ * t);
    float z_local = amplitude_ * sinf(freq_z_ * t + phase_z_);

    // Aplicar rotación global en eje X
    float cos_x = cosf(rotation_x_);
    float sin_x = sinf(rotation_x_);
    float y_rot = y_local * cos_x - z_local * sin_x;
    float z_rot = y_local * sin_x + z_local * cos_x;

    // Aplicar rotación global en eje Y
    float cos_y = cosf(rotation_y_);
    float sin_y = sinf(rotation_y_);
    float x_final = x_local * cos_y - z_rot * sin_y;
    float z_final = x_local * sin_y + z_rot * cos_y;

    // Retornar coordenadas rotadas
    x = x_final;
    y = y_rot;
    z = z_final;
}

float LissajousShape::getScaleFactor(float screen_height) const {
    // Factor de escala para física: proporcional a la amplitud de la curva
    // Amplitud base = 84px (0.35 * 240px en resolución 320x240)
    const float BASE_SIZE = 84.0f;
    float current_size = screen_height * LISSAJOUS_SIZE_FACTOR;
    return current_size / BASE_SIZE;
}
