"""
test_arc5_mastering.py - Test suite for ARC 5: T081-T100

Tests all mastering, export, and performance functionality.
"""

import sys
import os
import unittest
from pathlib import Path

# Add paths
sys.path.insert(0, str(Path("C:/ProgramData/Ableton/Live 12 Suite/Resources/MIDI Remote Scripts/AbletonMCP_AI/AbletonMCP_AI/MCP_Server")))

from mastering_engine import (
    MasteringEngine,
    ProfessionalMasteringChain,
    LUFSMeteringEngine,
    ClubTuningEngine,
    AutoExportEngine,
    RealtimeDiagnostics,
    TracklistGenerator,
    StreamingNormalization,
    MixdownCleanup,
    DynamicEQEngine,
    OverlapSafetyAudit,
    HardwareIntegration,
    BailoutSystem,
    PerformanceMonitor,
    get_mastering_engine,
    run_mastering_check,
    export_for_platform,
    start_3hour_performance
)


class TestT081MasteringChain(unittest.TestCase):
    """T081: Professional Mastering Chain"""
    
    def test_mastering_chain_initialization(self):
        """Test mastering chain initializes correctly"""
        chain = ProfessionalMasteringChain(genre="techno", platform="club")
        self.assertEqual(chain.genre, "techno")
        self.assertEqual(chain.platform, "club")
        self.assertGreater(len(chain.chain), 0)
    
    def test_chain_for_ableton_format(self):
        """Test chain converts to Ableton format"""
        chain = ProfessionalMasteringChain(genre="house", platform="streaming")
        ableton_chain = chain.get_chain_for_ableton()
        
        self.assertIsInstance(ableton_chain, list)
        self.assertGreater(len(ableton_chain), 0)
        
        # Check device structure
        for device in ableton_chain:
            self.assertIn('name', device)
            self.assertIn('type', device)
            self.assertIn('params', device)
    
    def test_preset_targets(self):
        """Test preset LUFS targets"""
        chain_streaming = ProfessionalMasteringChain(platform="streaming")
        self.assertEqual(chain_streaming.current_preset.target_lufs, -14.0)
        
        chain_club = ProfessionalMasteringChain(platform="club")
        self.assertEqual(chain_club.current_preset.target_lufs, -8.0)


class TestT082T083LUFSMetering(unittest.TestCase):
    """T082-T083: LUFS Metering and True Peak"""
    
    def test_lufs_measurement(self):
        """Test LUFS measurement"""
        meter = LUFSMeteringEngine()
        measurement = meter.measure_audio(estimated_peak_db=-3.0, estimated_rms_db=-12.0)
        
        self.assertIsNotNone(measurement.integrated)
        self.assertIsNotNone(measurement.true_peak)
        self.assertLess(measurement.true_peak, 0)  # Should be negative
    
    def test_true_peak_compliance(self):
        """Test true peak compliance check"""
        meter = LUFSMeteringEngine()
        measurement = meter.measure_audio(estimated_peak_db=-3.0, estimated_rms_db=-12.0)
        
        compliance = meter.check_true_peak_compliance(measurement)
        self.assertIn('compliant', compliance)
        self.assertIn('true_peak_db', compliance)
    
    def test_gain_adjustment_suggestion(self):
        """Test gain adjustment suggestion"""
        meter = LUFSMeteringEngine()
        meter.measure_audio(estimated_peak_db=-3.0, estimated_rms_db=-12.0)
        
        adjustment = meter.suggest_gain_adjustment('streaming')
        self.assertIn('adjustment_db', adjustment)
        self.assertIn('direction', adjustment)


class TestT084T085ClubTuning(unittest.TestCase):
    """T084-T085: Club Tuning and Headroom"""
    
    def test_club_configuration(self):
        """Test club tuning configuration"""
        engine = ClubTuningEngine()
        config = engine.configure_master_for_club()
        
        self.assertIn('bass_mono_frequency', config)
        self.assertIn('mono_sub_bass', config)
        self.assertTrue(config['mono_sub_bass'])
    
    def test_headroom_settings(self):
        """Test headroom settings by bus"""
        engine = ClubTuningEngine()
        
        for bus in ['drums', 'bass', 'music', 'master']:
            settings = engine.get_headroom_settings(bus)
            self.assertIn('target_headroom_db', settings)
            self.assertIn('peak_target_dbfs', settings)


class TestT086T087Export(unittest.TestCase):
    """T086-T087: Auto-Export and Stem Export"""
    
    def test_export_job_creation(self):
        """Test export job creation"""
        engine = AutoExportEngine()
        job = engine.create_export_job(format='wav', bit_depth=24, sample_rate=44100)
        
        self.assertEqual(job.format, 'wav')
        self.assertEqual(job.bit_depth, 24)
        self.assertEqual(job.sample_rate, 44100)
        self.assertIsNotNone(job.job_id)
    
    def test_export_presets(self):
        """Test export presets available"""
        engine = AutoExportEngine()
        presets = engine.get_export_presets()
        
        self.assertIn('club_master', presets)
        self.assertIn('streaming_master', presets)


class TestT088T089Diagnostics(unittest.TestCase):
    """T088-T089: Real-time Diagnostics"""
    
    def test_diagnostics_report(self):
        """Test diagnostics report generation"""
        diag = RealtimeDiagnostics()
        report = diag.get_diagnostic_report()
        
        self.assertIn('status', report)
        self.assertIn('recent_events_count', report)
    
    def test_emergency_procedures(self):
        """Test bailout emergency procedures"""
        bailout = BailoutSystem()
        procedures = bailout.get_emergency_procedures()
        
        self.assertGreater(len(procedures), 0)
        for proc in procedures:
            self.assertIn('name', proc)
            self.assertIn('trigger', proc)


class TestT090T091Tracklist(unittest.TestCase):
    """T090-T091: Tracklist and Profiler"""
    
    def test_tracklist_generation(self):
        """Test tracklist generation"""
        gen = TracklistGenerator()
        gen.add_entry(0, 128.0, "Am", 0.3, "Intro")
        gen.add_entry(64, 128.0, "Am", 1.0, "Drop")
        
        tracklist = gen.generate_tracklist(format='text')
        self.assertIsInstance(tracklist, str)
        self.assertIn('Intro', tracklist)
    
    def test_profiler_chart(self):
        """Test profiler chart generation"""
        gen = TracklistGenerator()
        gen.add_entry(0, 128.0, "Am", 0.3, "Intro")
        gen.add_entry(64, 130.0, "Fm", 1.0, "Drop")
        
        chart = gen.generate_profiler_chart()
        self.assertIn('bpm_timeline', chart)
        self.assertIn('energy_timeline', chart)
        self.assertIn('statistics', chart)


class TestT092StreamingNormalization(unittest.TestCase):
    """T092: Streaming Normalization"""
    
    def test_platform_targets(self):
        """Test platform-specific targets"""
        norm = StreamingNormalization()
        
        spotify = norm.get_platform_target('spotify')
        self.assertEqual(spotify['lufs'], -14.0)
        
        club = norm.get_platform_target('club')
        self.assertEqual(club['lufs'], -8.0)
    
    def test_normalization_report(self):
        """Test full platform report"""
        norm = StreamingNormalization()
        report = norm.get_all_platforms_report(-12.0)
        
        self.assertIn('platforms', report)
        self.assertGreater(len(report['platforms']), 0)


class TestT093MixdownCleanup(unittest.TestCase):
    """T093: Mixdown Cleanup"""
    
    def test_track_analysis(self):
        """Test track analysis for cleanup"""
        cleanup = MixdownCleanup()
        
        # Mock tracks
        tracks = [
            {'name': 'Kick', 'index': 0, 'mute': False, 'clips': [1, 2]},
            {'name': 'Unused Track', 'index': 1, 'mute': True, 'clips': []},
            {'name': 'Temp Backup', 'index': 2, 'mute': True, 'clips': []}
        ]
        
        analysis = cleanup.analyze_tracks(tracks)
        self.assertIn('cleanup_candidates', analysis)
        self.assertGreaterEqual(analysis['candidates_count'], 1)


class TestT094T095DynamicEQ(unittest.TestCase):
    """T094-T095: Dynamic EQ and M/S Processing"""
    
    def test_ms_configuration(self):
        """Test M/S EQ configuration"""
        eq = DynamicEQEngine()
        config = eq.get_ms_eq_configuration(side_hp_freq=100.0)
        
        self.assertIn('mid_channel', config)
        self.assertIn('side_channel', config)
        self.assertEqual(config['side_channel']['highpass_freq'], 100.0)
    
    def test_dynamic_bands(self):
        """Test dynamic EQ bands creation"""
        eq = DynamicEQEngine()
        bands = eq.get_soothe2_style_config([250.0, 500.0, 2000.0])
        
        self.assertEqual(len(bands), 3)
        for band in bands:
            self.assertIn('frequency_hz', band)
            self.assertIn('dynamic_params', band)


class TestT096OverlapSafety(unittest.TestCase):
    """T096: Overlap Safety Audit"""
    
    def test_gain_staging_audit(self):
        """Test gain staging audit"""
        audit = OverlapSafetyAudit()
        
        # Mock tracks
        tracks = [
            {'name': 'Drums', 'volume': 0.95},  # High - should warn
            {'name': 'Bass', 'volume': 0.75},    # Normal
            {'name': 'Music', 'volume': 0.20},  # Low - might suggest removal
        ]
        
        result = audit.audit_gain_staging(tracks)
        self.assertIn('findings', result)
        self.assertIn('high_risk_count', result)


class TestT097HardwareIntegration(unittest.TestCase):
    """T097: Hardware Integration"""
    
    def test_pioneer_mapping(self):
        """Test Pioneer controller mapping"""
        hw = HardwareIntegration()
        mapping = hw.create_ableton_mapping('pioneer')
        
        self.assertEqual(mapping['hardware'], 'pioneer')
        self.assertIn('mappings', mapping)
    
    def test_xone_mapping(self):
        """Test Xone controller mapping"""
        hw = HardwareIntegration()
        mapping = hw.create_ableton_mapping('xone')
        
        self.assertEqual(mapping['hardware'], 'xone')


class TestT098Bailout(unittest.TestCase):
    """T098: Bailout System"""
    
    def test_bailout_procedures(self):
        """Test bailout emergency procedures"""
        bailout = BailoutSystem()
        procedures = bailout.get_emergency_procedures()
        
        self.assertGreater(len(procedures), 0)
        
        # Check for 'Loop and Fade' procedure
        loop_fade = [p for p in procedures if p['name'] == 'Loop and Fade']
        self.assertEqual(len(loop_fade), 1)


class TestT099T100Performance(unittest.TestCase):
    """T099-T100: Performance Monitoring"""
    
    def test_performance_plan(self):
        """Test 3-hour performance plan generation"""
        monitor = PerformanceMonitor()
        plan = monitor.generate_3hour_performance_plan()
        
        self.assertEqual(plan['duration_hours'], 3)
        self.assertEqual(plan['check_interval_minutes'], 5)
        self.assertEqual(plan['total_checks'], 36)
    
    def test_performance_start(self):
        """Test performance monitoring start"""
        result = start_3hour_performance(None)
        
        self.assertIn('plan', result)
        self.assertIn('initial_health', result)
        self.assertEqual(result['plan']['duration_hours'], 3)


class TestIntegration(unittest.TestCase):
    """Integration tests for full MasteringEngine"""
    
    def test_full_engine_initialization(self):
        """Test complete engine initialization"""
        engine = get_mastering_engine(genre="techno", platform="club")
        
        self.assertIsNotNone(engine.mastering_chain)
        self.assertIsNotNone(engine.lufs_meter)
        self.assertIsNotNone(engine.export_engine)
        self.assertIsNotNone(engine.diagnostics)
        self.assertIsNotNone(engine.performance)
    
    def test_full_status_report(self):
        """Test complete status report"""
        engine = get_mastering_engine()
        status = engine.get_full_status()
        
        self.assertIn('mastering_chain', status)
        self.assertIn('lufs_meter', status)
        self.assertIn('export_engine', status)


def run_tests():
    """Run all tests and report results"""
    print("=" * 70)
    print("ARC 5: Mastering, Export & Performance - T081-T100 Test Suite")
    print("=" * 70)
    
    # Create test suite
    loader = unittest.TestLoader()
    suite = unittest.TestSuite()
    
    # Add all test classes
    test_classes = [
        TestT081MasteringChain,
        TestT082T083LUFSMetering,
        TestT084T085ClubTuning,
        TestT086T087Export,
        TestT088T089Diagnostics,
        TestT090T091Tracklist,
        TestT092StreamingNormalization,
        TestT093MixdownCleanup,
        TestT094T095DynamicEQ,
        TestT096OverlapSafety,
        TestT097HardwareIntegration,
        TestT098Bailout,
        TestT099T100Performance,
        TestIntegration
    ]
    
    for test_class in test_classes:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    
    # Run tests
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)
    
    # Print summary
    print("\n" + "=" * 70)
    print("TEST SUMMARY")
    print("=" * 70)
    print(f"Tests run: {result.testsRun}")
    print(f"Failures: {len(result.failures)}")
    print(f"Errors: {len(result.errors)}")
    print(f"Skipped: {len(result.skipped)}")
    print(f"Success rate: {(result.testsRun - len(result.failures) - len(result.errors)) / result.testsRun * 100:.1f}%")
    
    if result.wasSuccessful():
        print("\n[OK] All tests passed!")
        return 0
    else:
        print("\n[WARNING] Some tests failed")
        return 1


if __name__ == "__main__":
    exit_code = run_tests()
    sys.exit(exit_code)
