#!/usr/bin/env python3
"""
Test script para BLOQUE 3: Hardware MIDI Integration (T166-T180)

Este script prueba todas las funcionalidades del bloque 3 sin necesidad
de conexión a Ableton Live.
"""

import sys
import json

# Añadir path para import
sys.path.insert(0, r"C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\AbletonMCP_AI\MCP_Server")

from hardware_integration import (
    # T166
    get_hardware_mapping,
    HardwareType,
    CCMapping,
    NoteMapping,
    # T167
    bind_filter_to_bus_async,
    AsyncFilterController,
    # T168
    toggle_track_monitor,
    TrackMonitorController,
    # T169
    start_midi_clock_sync,
    stop_midi_clock_sync,
    get_midi_clock_status,
    # T170
    update_gain_staging_from_fader,
    get_gain_staging_status,
    # T171
    trigger_fill_from_pad,
    # T172
    trigger_panic_button,
    release_panic_button,
    # T173
    indicate_export_on_hardware,
    # T174
    start_cpu_monitoring,
    stop_cpu_monitoring,
    get_cpu_load,
    # T175
    trigger_scene_from_hardware,
    set_scene_quantization,
    # T176
    activate_performance_mode,
    deactivate_performance_mode,
    handle_performance_fader,
    # T177
    update_humanize_from_knob,
    # T178
    start_silence_detection,
    stop_silence_detection,
    # T179
    apply_nudge_forward,
    apply_nudge_backward,
    # T180
    trigger_visualization_macro,
    get_visualization_macros,
    # Manager
    get_complete_hardware_status,
)

def test_t166():
    """Test T166: Hardware Mapping"""
    print("\n" + "="*60)
    print("T166: Get Hardware Mapping")
    print("="*60)
    
    for hw in ["xone_k2", "akai_apc40", "pioneer_ddj"]:
        result = get_hardware_mapping(hw)
        print(f"\n{hw.upper()}:")
        print(f"  CC mappings: {result['cc_count']}")
        print(f"  Note mappings: {result['note_count']}")
        print(f"  Status: {result['status']}")
    
    return True

def test_t167():
    """Test T167: Filter Binding"""
    print("\n" + "="*60)
    print("T167: Async Filter Binding")
    print("="*60)
    
    import asyncio
    
    async def run_test():
        result = await bind_filter_to_bus_async(1, "music_bus", "xone_k2")
        print(f"\nFilter CC1 -> music_bus:")
        print(f"  Status: {result['status']}")
        print(f"  Smoothing: {result['smoothing']}")
        print(f"  Message: {result['message']}")
        return True
    
    return asyncio.run(run_test())

def test_t168():
    """Test T168: Track Monitor"""
    print("\n" + "="*60)
    print("T168: Track Monitor Control")
    print("="*60)
    
    result = toggle_track_monitor(0)
    print(f"\nToggle track 0 monitor:")
    print(f"  Track: {result['track_index']}")
    print(f"  Monitor: {result['monitor_active']}")
    
    return True

def test_t169():
    """Test T169: MIDI Clock Sync"""
    print("\n" + "="*60)
    print("T169: MIDI Clock Sync")
    print("="*60)
    
    start_result = start_midi_clock_sync()
    print(f"\nStart sync:")
    print(f"  Status: {start_result['status']}")
    print(f"  PPQN: {start_result['ppqn']}")
    
    status = get_midi_clock_status()
    print(f"\nStatus:")
    print(f"  Running: {status['running']}")
    print(f"  Current BPM: {status['current_bpm']}")
    
    stop_result = stop_midi_clock_sync()
    print(f"\nStop sync:")
    print(f"  Status: {stop_result['status']}")
    
    return True

def test_t170():
    """Test T170: Gain Staging from Fader"""
    print("\n" + "="*60)
    print("T170: Gain Staging from Fader")
    print("="*60)
    
    for cc in [0, 64, 100, 127]:
        result = update_gain_staging_from_fader(cc)
        print(f"\nFader CC={cc}:")
        print(f"  Target LUFS: {result['target_lufs']} dB")
        print(f"  Range: {result['normalized']:.2f}")
    
    return True

def test_t171():
    """Test T171: Fill Trigger from Pad"""
    print("\n" + "="*60)
    print("T171: Fill Trigger from Pad")
    print("="*60)
    
    for pad in [1, 2, 3, 4]:
        result = trigger_fill_from_pad(pad)
        print(f"\nPad {pad}:")
        print(f"  Fill: {result['fill_name']}")
        print(f"  Density: {result['density']}")
        print(f"  Section: {result['section']}")
    
    return True

def test_t172():
    """Test T172: Panic Button"""
    print("\n" + "="*60)
    print("T172: Panic Button")
    print("="*60)
    
    result = trigger_panic_button()
    print(f"\nPanic triggered:")
    print(f"  Status: {result['status']}")
    print(f"  Affected tracks: {result['affected_tracks']}")
    
    release = release_panic_button()
    print(f"\nPanic released:")
    print(f"  Status: {release['status']}")
    
    return True

def test_t173():
    """Test T173: Export Feedback"""
    print("\n" + "="*60)
    print("T173: Export Feedback (no MIDI port)")
    print("="*60)
    
    result = indicate_export_on_hardware()
    print(f"\nExport indication:")
    print(f"  Status: {result['status']}")
    print(f"  Pattern: {result['led_pattern']}")
    
    return True

def test_t174():
    """Test T174: CPU Monitoring"""
    print("\n" + "="*60)
    print("T174: CPU Monitoring")
    print("="*60)
    
    start = start_cpu_monitoring(1000)
    print(f"\nStart monitoring:")
    print(f"  Status: {start['status']}")
    print(f"  Interval: {start['interval_ms']} ms")
    
    import time
    time.sleep(0.5)
    
    status = get_cpu_load()
    print(f"\nCPU Load:")
    print(f"  Load: {status['cpu_load_percent']}%")
    print(f"  Monitoring: {status['monitoring']}")
    
    stop = stop_cpu_monitoring()
    print(f"\nStop monitoring:")
    print(f"  Status: {stop['status']}")
    
    return True

def test_t175():
    """Test T175: Scene Trigger"""
    print("\n" + "="*60)
    print("T175: Scene Trigger with Quantization")
    print("="*60)
    
    result = trigger_scene_from_hardware(0, "1bar")
    print(f"\nTrigger scene 0:")
    print(f"  Scene: {result['scene_index']}")
    print(f"  Quantization: {result['quantization']}")
    print(f"  Beats: {result['quantization_beats']}")
    
    modes = set_scene_quantization("2bar")
    print(f"\nSet global quantization:")
    print(f"  Mode: {modes['quantization']}")
    print(f"  Beats: {modes['beats']}")
    
    return True

def test_t176():
    """Test T176: Performance Mode"""
    print("\n" + "="*60)
    print("T176: Performance Mode")
    print("="*60)
    
    for layout in ["default", "dj", "live"]:
        result = activate_performance_mode(layout)
        print(f"\nActivate {layout}:")
        print(f"  Status: {result['status']}")
        print(f"  Layout: {result['layout']}")
        print(f"  Faders: {result['fader_count']}")
        
        # Simular movimiento de fader
        fader = handle_performance_fader(0, 100)
        print(f"  Fader 0 @ 100: {fader['assignment']['name']}")
        
        deactivate_performance_mode()
    
    return True

def test_t177():
    """Test T177: Humanize Macro"""
    print("\n" + "="*60)
    print("T177: Humanize Macro")
    print("="*60)
    
    for cc in [0, 32, 64, 96, 127]:
        result = update_humanize_from_knob(cc)
        print(f"\nKnob CC={cc}:")
        print(f"  Intensity: {result['intensity']}")
        print(f"  Level: {result['level']}")
    
    return True

def test_t178():
    """Test T178: Silence Detection"""
    print("\n" + "="*60)
    print("T178: Silence Detection & Backup")
    print("="*60)
    
    result = start_silence_detection(-60.0, 3000)
    print(f"\nStart detection:")
    print(f"  Status: {result['status']}")
    print(f"  Threshold: {result['threshold_db']} dB")
    print(f"  Duration: {result['duration_ms']} ms")
    print(f"  Action: {result['action_on_silence']}")
    
    import time
    time.sleep(0.2)
    
    stop = stop_silence_detection()
    print(f"\nStop detection:")
    print(f"  Status: {stop['status']}")
    
    return True

def test_t179():
    """Test T179: Nudging"""
    print("\n" + "="*60)
    print("T179: Async Nudging")
    print("="*60)
    
    result = apply_nudge_forward(5.0)
    print(f"\nNudge forward 5ms:")
    print(f"  Direction: {result['direction']}")
    print(f"  Amount: {result['amount_ms']} ms")
    print(f"  Samples @ 48k: {result['samples_48k']}")
    
    back = apply_nudge_backward(3.0)
    print(f"\nNudge backward 3ms:")
    print(f"  Direction: {back['direction']}")
    print(f"  Amount: {back['amount_ms']} ms")
    
    return True

def test_t180():
    """Test T180: Visualization Macros"""
    print("\n" + "="*60)
    print("T180: Visualization Macros")
    print("="*60)
    
    macros = get_visualization_macros()
    print(f"\nAvailable macros:")
    for name in macros['available_macros']:
        desc = macros['descriptions'].get(name, "")
        print(f"  - {name}: {desc}")
    
    # Trigger some (no MIDI port available, but code runs)
    for macro in ['strobe_beat', 'level_meter']:
        result = trigger_visualization_macro(macro)
        print(f"\nTrigger {macro}:")
        print(f"  Status: {result['status']}")
    
    return True

def test_complete_status():
    """Test complete hardware status"""
    print("\n" + "="*60)
    print("Complete Hardware Status (T166-T180)")
    print("="*60)
    
    result = get_complete_hardware_status()
    
    print(f"\nStatus keys:")
    for key in result.keys():
        print(f"  - {key}")
    
    print(f"\nMido available: {result['mido_available']}")
    print(f"Timestamp: {result['timestamp']}")
    
    return True

def main():
    print("\n" + "="*60)
    print("BLOQUE 3: HARDWARE MIDI INTEGRATION (T166-T180)")
    print("Testing all components...")
    print("="*60)
    
    tests = [
        test_t166,
        test_t167,
        test_t168,
        test_t169,
        test_t170,
        test_t171,
        test_t172,
        test_t173,
        test_t174,
        test_t175,
        test_t176,
        test_t177,
        test_t178,
        test_t179,
        test_t180,
        test_complete_status,
    ]
    
    passed = 0
    failed = 0
    
    for test in tests:
        try:
            if test():
                passed += 1
                print(f"\n  [OK] {test.__name__} PASSED")
            else:
                failed += 1
                print(f"\n  [FAIL] {test.__name__} FAILED")
        except Exception as e:
            failed += 1
            print(f"\n  [ERR] {test.__name__} ERROR: {e}")
    
    print("\n" + "="*60)
    print("TEST SUMMARY")
    print("="*60)
    print(f"Passed: {passed}/{len(tests)}")
    print(f"Failed: {failed}/{len(tests)}")
    
    if failed == 0:
        print("\n[OK] ALL T166-T180 TESTS PASSED!")
    else:
        print(f"\n[FAIL] {failed} TEST(S) FAILED")
    
    return failed == 0

if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)
