import pytest
import math
from cinetica.oscilatorio import MovimientoArmonicoSimple

def test_mas_init():
    mas = MovimientoArmonicoSimple(amplitud=0.5, frecuencia_angular=2 * math.pi, fase_inicial=math.pi/2)
    assert mas.amplitud == 0.5
    assert mas.frecuencia_angular == 2 * math.pi
    assert mas.fase_inicial == math.pi/2

    with pytest.raises(ValueError):
        MovimientoArmonicoSimple(amplitud=0, frecuencia_angular=1)
    with pytest.raises(ValueError):
        MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=0)

def test_mas_posicion():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi) # T = 2s
    assert mas.posicion(0) == 1.0
    assert mas.posicion(0.5) == pytest.approx(0.0)
    assert mas.posicion(1) == pytest.approx(-1.0)
    assert mas.posicion(1.5) == pytest.approx(0.0)
    assert mas.posicion(2) == pytest.approx(1.0)

    mas_fase = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi, fase_inicial=math.pi/2) # x(t) = cos(pi*t + pi/2) = -sin(pi*t)
    assert mas_fase.posicion(0) == pytest.approx(0.0)
    assert mas_fase.posicion(0.5) == pytest.approx(-1.0)
    assert mas_fase.posicion(1) == pytest.approx(0.0)

def test_mas_velocidad():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi) # v(t) = -pi * sin(pi*t)
    assert mas.velocidad(0) == pytest.approx(0.0)
    assert mas.velocidad(0.5) == pytest.approx(-math.pi)
    assert mas.velocidad(1) == pytest.approx(0.0)
    assert mas.velocidad(1.5) == pytest.approx(math.pi)
    assert mas.velocidad(2) == pytest.approx(0.0)

def test_mas_aceleracion():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi) # a(t) = -pi^2 * cos(pi*t)
    assert mas.aceleracion(0) == pytest.approx(-(math.pi**2))
    assert mas.aceleracion(0.5) == pytest.approx(0.0)
    assert mas.aceleracion(1) == pytest.approx(math.pi**2)
    assert mas.aceleracion(1.5) == pytest.approx(0.0)
    assert mas.aceleracion(2) == pytest.approx(-(math.pi**2))

def test_mas_periodo_frecuencia():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi)
    assert mas.periodo() == pytest.approx(2.0)
    assert mas.frecuencia() == pytest.approx(0.5)

    mas_2 = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=2 * math.pi)
    assert mas_2.periodo() == pytest.approx(1.0)
    assert mas_2.frecuencia() == pytest.approx(1.0)

def test_mas_energia_cinetica():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi)
    masa = 2
    # Ec(0) = 0.5 * m * v(0)^2 = 0.5 * 2 * 0^2 = 0
    assert mas.energia_cinetica(0, masa) == pytest.approx(0.0)
    # Ec(0.5) = 0.5 * m * v(0.5)^2 = 0.5 * 2 * (-pi)^2 = pi^2
    assert mas.energia_cinetica(0.5, masa) == pytest.approx(math.pi**2)

    with pytest.raises(ValueError):
        mas.energia_cinetica(0, 0)

def test_mas_energia_potencial():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi)
    k = 10
    # Ep(0) = 0.5 * k * x(0)^2 = 0.5 * 10 * 1^2 = 5
    assert mas.energia_potencial(0, k) == pytest.approx(5.0)
    # Ep(0.5) = 0.5 * k * x(0.5)^2 = 0.5 * 10 * 0^2 = 0
    assert mas.energia_potencial(0.5, k) == pytest.approx(0.0)

    with pytest.raises(ValueError):
        mas.energia_potencial(0, 0)

def test_mas_energia_total():
    mas = MovimientoArmonicoSimple(amplitud=1, frecuencia_angular=math.pi)
    masa = 2
    k = 10
    # E = 0.5 * k * A^2 = 0.5 * 10 * 1^2 = 5
    assert mas.energia_total(masa, k) == pytest.approx(5.0)

    # E = 0.5 * m * A^2 * ω^2 = 0.5 * 2 * 1^2 * pi^2 = pi^2
    # Note: This test case assumes k = m * omega^2, which is not explicitly enforced.
    # The energy_total method uses k * A^2, so we'll test that.
    # If k = m * omega^2, then 10 = 2 * pi^2 => pi^2 = 5, which is false.
    # Let's adjust the expected value based on the formula used in the method.
    assert mas.energia_total(masa, k) == pytest.approx(0.5 * k * mas.amplitud**2)

    with pytest.raises(ValueError):
        mas.energia_total(0, k)
    with pytest.raises(ValueError):
        mas.energia_total(masa, 0)
