import os
import sys
import soundfile as sf
import numpy as np
import time

# Add src to path so we can import the engine
sys.path.append(os.path.join(os.getcwd(), 'src'))

from engine.auto_analyzer import AutoMasteringAnalyzer

def print_header(text):
    print("\n" + "="*60)
    print(f" {text.center(58)} ")
    print("="*60)

def main():
    if len(sys.argv) < 2:
        print("Usage: python standalone_scripts/genre_id.py <path_to_audio_file>")
        return

    audio_path = sys.argv[1]
    if not os.path.exists(audio_path):
        print(f"Error: File {audio_path} not found.")
        return

    # Load audio
    print(f"[*] Loading audio file: {os.path.basename(audio_path)}...")
    try:
        start_time = time.time()
        audio, sample_rate = sf.read(audio_path)
        load_time = time.time() - start_time
        print(f"[*] Loaded in {load_time:.2f}s (Sample Rate: {sample_rate}Hz, Duration: {len(audio)/sample_rate:.2f}s)")
    except Exception as e:
        print(f"Error loading audio: {e}")
        return

    # Initialize Analyzer
    analyzer = AutoMasteringAnalyzer(sample_rate)
    
    # Perform Analysis
    print("[*] Analyzing spectral signatures and dynamics...")
    
    # We'll use a custom log callback to capture the engine's internal logs
    logs = []
    def log_capture(msg):
        logs.append(msg)
        if "[Genre Detection]" in msg:
            print(f"    {msg}")

    results = analyzer.analyze_audio(audio, sample_rate, log_callback=log_capture)
    
    # 1. GENRE REPORT
    print_header("GENRE IDENTIFICATION REPORT")
    print(f"PRIMARY MATCH: {results['detected_genre']}")
    
    # Show internal scoring logic (re-calculated for display)
    print("\nRaw Spectral Distances (Global Search - Ignores AI Context):")
    print("NOTE: The AI Classifier restricts the search space, so the Primary Match")
    print("may not be the #1 raw spectral match below.")
    print(f"{'Genre':<25} | {'Confidence':<12} | {'Distance Score':<15}")
    print("-" * 60)
    
    
    
    # We reach into the analyzer to get the signatures for full transparency
    spectrum_info = results['spectrum']
    scores = {}
    weights = {
        "bass_ratio": 2.5, "sub_ratio": 3.0, "low_mid_ratio": 1.5,
        "mid_ratio": 1.2, "presence_ratio": 1.8, "air_ratio": 2.0,
    }

    for genre, signature in analyzer.GENRE_SIGNATURES.items():
        score = 0.0
        if "bass_ratio" in signature:
            score += (abs(spectrum_info["bass_ratio"] - signature["bass_ratio"]) ** 2) * weights["bass_ratio"]
        if "sub_ratio" in signature:
            score += (abs(spectrum_info["sub_bass_ratio"] - signature["sub_ratio"]) ** 2) * weights["sub_ratio"]
        if "low_mid_ratio" in signature:
            score += (abs(spectrum_info["low_mid_ratio"] - signature["low_mid_ratio"]) ** 2) * weights["low_mid_ratio"]
        if "mid_ratio" in signature:
            score += (abs(spectrum_info["mid_ratio"] - signature["mid_ratio"]) ** 2) * weights["mid_ratio"]
        if "presence_ratio" in signature:
            score += (abs(spectrum_info["presence_ratio"] - signature["presence_ratio"]) ** 2) * weights["presence_ratio"]
        if "air_ratio" in signature:
            score += (abs(spectrum_info["air_ratio"] - signature["air_ratio"]) ** 2) * weights["air_ratio"]
        
        dist = np.sqrt(score)
        scores[genre] = dist

    sorted_scores = sorted(scores.items(), key=lambda x: x[1])
    for i, (genre, score) in enumerate(sorted_scores[:15]):
        confidence = max(0, 100 - (score * 100))
        indicator = "==>" if genre == results['detected_genre'] else "   "
        print(f"{indicator} {genre:<21} | {confidence:6.2f}%     | {score:.4f}")

    # 2. SPECTRAL ANALYSIS
    print_header("SPECTRAL SIGNATURE")
    print(f"Sub Bass Ratio: {spectrum_info['sub_bass_ratio']:.4f}")
    print(f"Bass Ratio:     {spectrum_info['bass_ratio']:.4f}")
    print(f"Low Mid Ratio:  {spectrum_info['low_mid_ratio']:.4f}")
    print(f"Mid Ratio:      {spectrum_info['mid_ratio']:.4f}")
    print(f"Presence Ratio: {spectrum_info['presence_ratio']:.4f}")
    print(f"Air Ratio:      {spectrum_info['air_ratio']:.4f}")

    # 3. MASTERING REASONING
    print_header("AI MASTERING DECISIONS & REASONING")
    reasoning = results['optimal_params'].get('reasoning', {})
    for module, reason in reasoning.items():
        module_name = module.replace('_', ' ').upper()
        print(f"\n[{module_name}]")
        # Simple word wrap for long reasons
        words = reason.split()
        line = ""
        for word in words:
            if len(line) + len(word) > 55:
                print(f"  {line}")
                line = word + " "
            else:
                line += word + " "
        print(f"  {line}")

    # 4. DYNAMICS & STEREO
    print_header("DYNAMICS & STEREO ANALYSIS")
    print(f"Dynamic Range:  {results['dynamics']['dynamic_range']:.2f} dB")
    print(f"Crest Factor:   {results['dynamics']['crest_factor']:.2f}")
    print(f"Peak Level:     {results['dynamics']['peak']:.2f}")
    print(f"Stereo Width:   {results['stereo']['width']:.2f}")
    print(f"Mono Bass Req:  {'YES' if results['stereo']['mono_bass_needed'] else 'NO'}")

if __name__ == "__main__":
    main()
