"""Unit tests for _estimate_tempo function."""
import unittest
import numpy as np

from reaper_mcp.audio.audio_analysis import _estimate_tempo


class TestEstimateTempo(unittest.TestCase):
    """Tests for the _estimate_tempo function."""
    
    def setUp(self):
        """Set up test parameters."""
        self.sample_rate = 44100
        
    def _generate_click_track(self, bpm: float, duration: float = 4.0) -> np.ndarray:
        """Generate a simple click track at a given BPM."""
        samples = int(self.sample_rate * duration)
        audio = np.zeros(samples)
        
        # Calculate samples per beat
        beats_per_second = bpm / 60.0
        samples_per_beat = int(self.sample_rate / beats_per_second)
        
        # Add clicks (short bursts of noise)
        click_duration = int(self.sample_rate * 0.01)  # 10ms clicks
        
        for i in range(int(duration * beats_per_second)):
            start_idx = i * samples_per_beat
            end_idx = min(start_idx + click_duration, samples)
            if start_idx < samples:
                audio[start_idx:end_idx] = 0.5
        
        return audio
    
    def test_estimate_tempo_120_bpm(self):
        """Test tempo estimation with 120 BPM click track."""
        audio = self._generate_click_track(120.0)
        tempo = _estimate_tempo(audio, self.sample_rate)
        # Allow some tolerance in tempo detection
        self.assertGreaterEqual(tempo, 115.0, f"Tempo {tempo} is too low for 120 BPM")
        self.assertLessEqual(tempo, 125.0, f"Tempo {tempo} is too high for 120 BPM")
    
    def test_estimate_tempo_90_bpm(self):
        """Test tempo estimation with 90 BPM click track."""
        audio = self._generate_click_track(90.0)
        tempo = _estimate_tempo(audio, self.sample_rate)
        # Allow some tolerance
        self.assertGreaterEqual(tempo, 85.0, f"Tempo {tempo} is too low for 90 BPM")
        self.assertLessEqual(tempo, 95.0, f"Tempo {tempo} is too high for 90 BPM")
    
    def test_estimate_tempo_140_bpm(self):
        """Test tempo estimation with 140 BPM click track."""
        audio = self._generate_click_track(140.0)
        tempo = _estimate_tempo(audio, self.sample_rate)
        # Allow some tolerance
        self.assertGreaterEqual(tempo, 135.0, f"Tempo {tempo} is too low for 140 BPM")
        self.assertLessEqual(tempo, 145.0, f"Tempo {tempo} is too high for 140 BPM")
    
    def test_estimate_tempo_silence(self):
        """Test tempo estimation with silence - should return default 120.0."""
        audio = np.zeros(int(self.sample_rate * 4.0))
        tempo = _estimate_tempo(audio, self.sample_rate)
        self.assertEqual(tempo, 120.0, f"Expected 120.0 for silence but got {tempo}")
    
    def test_estimate_tempo_clamping_high(self):
        """Test that tempo is clamped to maximum 180 BPM."""
        # Create a very fast click track (would be >180 BPM)
        audio = self._generate_click_track(200.0, duration=2.0)
        tempo = _estimate_tempo(audio, self.sample_rate)
        self.assertLessEqual(tempo, 180.0, f"Tempo {tempo} exceeds maximum 180.0")
    
    def test_estimate_tempo_clamping_low(self):
        """Test that tempo is clamped to minimum 60 BPM."""
        # Create a very slow click track (would be <60 BPM)
        audio = self._generate_click_track(40.0, duration=8.0)
        tempo = _estimate_tempo(audio, self.sample_rate)
        self.assertGreaterEqual(tempo, 60.0, f"Tempo {tempo} below minimum 60.0")
