import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

import numpy as np
import pytest
from app.core.sub_tab_dsp import SubTabDSPEngine

def test_speed_ratio():
    sr = 44100
    y = np.sin(2 * np.pi * 440 * np.linspace(0, 1, sr, endpoint=False)).astype(np.float32)
    # Pitch-preserving speed change
    y_stretched = SubTabDSPEngine.change_speed(y, sr, 2.0, preserve_pitch=True)
    assert abs(len(y_stretched) - sr // 2) < 2000 # Librosa might have frame alignment differences
    
    # Simple resampling speed change
    y_resampled = SubTabDSPEngine.change_speed(y, sr, 2.0, preserve_pitch=False)
    assert len(y_resampled) == sr // 2

def test_normalize():
    y = np.array([0.1, -0.5, 0.2, 0.4], dtype=np.float32)
    y_norm = SubTabDSPEngine.normalize(y, target_db=0.0)
    assert np.max(np.abs(y_norm)) == 1.0

def test_merge_back_to_parent():
    sr = 1000
    parent = np.ones(5000, dtype=np.float32)
    edited = np.zeros(2000, dtype=np.float32)
    
    # Merge at t=1.0s (index 1000), original duration 1.5s (1500 samples)
    res = SubTabDSPEngine.merge_back_to_parent(
        parent_track_audio=parent,
        sr=sr,
        edited_sub_audio=edited,
        start_seconds=1.0,
        original_duration_seconds=1.5
    )
    
    # Expected length: 5000 - 1500 + 2000 = 5500
    assert len(res) == 5500
    # Before 1.0s (1000 samples) should be mostly parent values (1.0)
    assert np.allclose(res[:900], 1.0)
    # Inside the edited range should be zero (except crossfades)
    assert np.allclose(res[1100:2900], 0.0)

def test_apply_volume_automation_envelope():
    sr = 44100
    duration = 2.0
    y = np.ones(int(sr * duration), dtype=np.float32) * 0.5  # Constant signal at -6dB

    # Simple fade in from -inf to 0dB over 1 second
    nodes = [
        {"time": 0.0, "db": -60.0}, # Effectively -inf
        {"time": 1.0, "db": 0.0},
        {"time": 2.0, "db": 0.0},
    ]
    
    y_automated = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, nodes)

    y_automated = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, nodes)

    # Check start: should be 0.5 * 10**(-30/20) due to clipping
    expected_start_val = 0.5 * (10**(-30/20.0))
    assert np.isclose(y_automated[0], expected_start_val, atol=1e-5)
    
    # Check at 0.5 seconds: interpolated to -15dB (halfway between -30dB and 0dB)
    # y * (10 ** (-15 / 20))
    expected_mid_val = 0.5 * (10**(-15/20.0))
    assert np.isclose(y_automated[int(0.5 * sr)], expected_mid_val, atol=1e-5)

    # Check at 1.0 seconds: should be 0.5 * (10**(0/20)) = 0.5
    assert np.isclose(y_automated[int(1.0 * sr)], 0.5, atol=1e-5)

    # Check at end: should be 0.5
    assert np.isclose(y_automated[-1], 0.5, atol=1e-5)

    # Test with empty nodes
    y_no_nodes = SubTabDSPEngine.apply_volume_automation_envelope(y, sr, [])
    assert np.array_equal(y_no_nodes, y)

