import os
import matplotlib
matplotlib.use('Agg') # Force non-interactive backend
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
from colorama import Fore, Style

class ReportGenerator:
    def __init__(self, output_dir):
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)

    def _prepare_data(self, filename, metrics, history, reference, strategy_log=None):
        from analyzer import AudioAnalyzer
        import soundfile as sf
        analyzer = AudioAnalyzer()
        
        score, penalties = analyzer.calculate_health_score(metrics)
        c_score, c_penalties = analyzer.calculate_coherence_score(metrics)
        o_score = analyzer.calculate_overall_score(metrics)
        verdict_title, verdict_desc = analyzer.get_verdict(score)
        
        # 7-Band Targets
        targets = {"sub": 4.0, "bass": 12.0, "mud": 15.0, "low_mid": 18.0, "mid": 15.0, "presence": 15.0, "air": 21.0}
        tonal_dev = {k: metrics['spectrum'].get(k, 0) - v for k, v in targets.items()}
        
        # Load audio data from disk for waveforms
        orig_path = history[0]['path']
        master_path = metrics['path']
        
        try:
            o_data, _ = sf.read(orig_path)
            m_data, _ = sf.read(master_path)
            o_env = analyzer.get_waveform_envelope(o_data)
            m_env = analyzer.get_waveform_envelope(m_data)
        except Exception as e:
            print(f"Warning: Could not load data for waveform: {e}")
            o_env = [0]*150
            m_env = [0]*150
        
        return {
            'filename': os.path.basename(filename),
            'date': datetime.now().strftime("%B %d, %Y"),
            'health_score': score,
            'coherence_score': c_score,
            'overall_score': o_score,
            'translation_score': metrics.get('translation_score', 0),
            'translation_penalties': metrics.get('translation_penalties', []),
            'punch_score': metrics.get('punch_factor', 0),
            'punch_penalties': metrics.get('punch_penalties', []),
            'cleanliness_score': metrics.get('cleanliness_score', 0),
            'cleanliness_penalties': metrics.get('cleanliness_penalties', []),
            'verdict': verdict_title,
            'verdict_desc': verdict_desc,
            'penalties': penalties + c_penalties,
            'metrics': metrics,
            'history': history,
            'tonal_dev': tonal_dev,
            'reference': reference,
            'strategy_log': strategy_log,
            'envelopes': {
                'original': o_env,
                'master': m_env
            }
        }

    def generate(self, filename, metrics, history, reference, formats, strategy_log=None):
        """Generate high-end visual reports in multiple formats."""
        # Ensure formats are clean
        formats = [f.strip().lower() for f in formats]
        
        base_name = os.path.splitext(os.path.basename(filename))[0]
        data = self._prepare_data(filename, metrics, history, reference, strategy_log=strategy_log)
        
        generated_files = []
        
        # 1. HTML Report (Interactive Storyboard)
        if 'html' in formats:
            path = os.path.join(self.output_dir, f"{base_name}_Storyboard.html")
            self._generate_html(path, data)
            generated_files.append(path)
            
        # 2. Graphical Dashboard (PDF/JPG)
        if 'pdf' in formats or 'jpg' in formats or 'png' in formats:
            fig = self._create_matplotlib_dashboard(data)
            
            if 'pdf' in formats:
                path = os.path.join(self.output_dir, f"{base_name}_Dashboard.pdf")
                fig.savefig(path, bbox_inches='tight', dpi=300)
                generated_files.append(path)
                
            if 'jpg' in formats or 'png' in formats:
                ext = 'jpg' if 'jpg' in formats else 'png'
                path = os.path.join(self.output_dir, f"{base_name}_Dashboard.{ext}")
                fig.savefig(path, bbox_inches='tight', dpi=150)
                generated_files.append(path)
                
            plt.close(fig)
            
        return generated_files

    def _generate_html(self, path, data):
        m = data['metrics']
        bg_color = "#131314"
        card_bg = "#1e1f20"
        accent = "#A8C7FA"
        
        def get_score_color(s):
            if s > 85: return "#c4eed0"
            if s > 60: return "#fff4a3"
            return "#f2b8b5"
        
        score_color = get_score_color(data['health_score'])

        # --- Visual Components ---
        
        # 1. Waveform SVG
        def make_waveform_svg(env, color):
            points = " ".join([f"{i*5},{100-v}" for i, v in enumerate(env)])
            return f'<polyline points="{points}" fill="none" stroke="{color}" stroke-width="2" />'

        # 2. Soundstage Arcs
        low_w = max(15, (1 - m['band_corr']['low']) * 100)
        mid_w = max(30, (1 - m['band_corr']['mid']) * 100)
        high_w = max(50, (1 - m['band_corr']['high']) * 100)

        # 3. Tonal Rows
        bands = ["sub", "bass", "mud", "low_mid", "mid", "presence", "air", "sparkle"]
        labels = ["Sub", "Bass", "Mud", "Low-Mid", "Mid", "Presence", "Air", "Sparkle"]
        tonal_rows = ""
        for i, k in enumerate(bands):
            dev = data['tonal_dev'].get(k, 0)
            width = min(80, abs(dev) * 8)
            bar_color = "#7ab3ef" if dev < 0 else "#fbc02d"
            if k == "sparkle": bar_color = "#A8C7FA" # Special color for sparkle
            align = "flex-end" if dev < 0 else "flex-start"
            tonal_rows += f"""
            <div class="tonal-row">
                <div class="tonal-label">{labels[i]}</div>
                <div class="tonal-track"><div class="tonal-bar" style="width:{width}%; background:{bar_color}; align-self:{align}; margin-{'left' if dev>=0 else 'right'}:50%"></div></div>
                <div class="tonal-value" style="color:{bar_color}">{dev:+.1f}%</div>
            </div>"""

        # 4. Evolution History
        evolution_html = ""
        for i, h in enumerate(data['history']):
            label = "Original" if i == 0 else f"Pass {i}"
            s = self._calculate_health_score_simple(h)
            evolution_html += f"""
            <div class="evo-node">
                <div class="evo-dot" style="background:{accent if i==len(data['history'])-1 else '#444'}"></div>
                <div class="evo-label">{label}</div>
                <div class="evo-score">{s}</div>
            </div>"""

        # 5. Micro-Metrics HTML
        micro_html = ""
        if 'micro' in m:
            mc = m['micro']
            def get_status_col(v, target, inv=False):
                return "#c4eed0" if (v > target if not inv else v < target) else "#fff4a3"
            
            # Fidelity Penalties Breakdown for HTML
            fid_penalties_html = ""
            for fid_type, p_list in [("Translation", data.get('translation_penalties', [])), 
                                    ("Punch", data.get('punch_penalties', [])), 
                                    ("Cleanliness", data.get('cleanliness_penalties', []))]:
                if p_list:
                    fid_penalties_html += f'<div style="margin-bottom: 10px;"><strong>{fid_type}:</strong> <span style="color: #f2b8b5;">{" | ".join(p_list)}</span></div>'

            micro_html = f"""
            <div class="card" style="margin-top: 24px;">
                <h2>High-Fidelity Analytics</h2>
                <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; text-align: center; margin-bottom: 30px;">
                    <div class="micro-stat">
                        <div class="micro-val" style="color: {get_status_col(mc['sparkle_energy'], 0.5)}">{mc['sparkle_energy']:.2f}%</div>
                        <div class="micro-lab">HF Sparkle (12k+)</div>
                    </div>
                    <div class="micro-stat">
                        <div class="micro-val" style="color: {get_status_col(mc['hf_sharpness'], 13.0)}">{mc['hf_sharpness']:.1f}dB</div>
                        <div class="micro-lab">Transient Bite</div>
                    </div>
                    <div class="micro-stat">
                        <div class="micro-val" style="color: {get_status_col(mc['phase_drift'], 0.05, True)}">{mc['phase_drift']:.3f}</div>
                        <div class="micro-lab">Phase Drift (Var)</div>
                    </div>
                    <div class="micro-stat">
                        <div class="micro-val" style="color: {get_status_col(mc['spectral_complexity'], 9.0)}">{mc['spectral_complexity']:.2f}</div>
                        <div class="micro-lab">Complexity (Bits)</div>
                    </div>
                </div>
                {f'<div style="border-top: 1px solid #333; padding-top: 20px; font-size: 13px;">{fid_penalties_html}</div>' if fid_penalties_html else ''}
            </div>"""

        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title>Mastering Report | {data['filename']}</title>
            <style>
                body {{ font-family: 'Segoe UI', system-ui, sans-serif; background: {bg_color}; color: #e3e3e3; margin: 0; padding: 40px; }}
                .container {{ max-width: 1100px; margin: 0 auto; }}
                .card {{ background: {card_bg}; border-radius: 24px; padding: 32px; border: 1px solid #333; margin-bottom: 24px; }}
                
                header {{ display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px; }}
                .health-gauge {{ width: 120px; height: 120px; border-radius: 50%; border: 6px solid {score_color}; display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(255,255,255,0.03); }}
                .verdict-badge {{ background: {score_color}; color: {bg_color}; padding: 4px 12px; border-radius: 20px; font-weight: 800; font-size: 12px; text-transform: uppercase; }}
                
                .grid {{ display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; }}
                h2 {{ font-size: 12px; text-transform: uppercase; letter-spacing: 2px; color: {accent}; margin-bottom: 24px; }}
                
                /* Soundstage */
                .stage {{ height: 200px; display: flex; justify-content: center; align-items: flex-end; position: relative; background: radial-gradient(circle at 50% 100%, #222, {card_bg}); border-radius: 100px 100px 0 0; overflow: hidden; }}
                .arc {{ position: absolute; border: 2px solid; border-bottom: none; border-radius: 50% 50% 0 0; }}
                .arc.low {{ width: {low_w}%; height: {low_w/2}%; border-color: #4CAF50; opacity: 0.8; }}
                .arc.mid {{ width: {mid_w}%; height: {mid_w/2}%; border-color: #2196F3; opacity: 0.6; }}
                .arc.high {{ width: {high_w}%; height: {high_w/2}%; border-color: {accent}; opacity: 0.4; }}
                
                /* Tonal Balance */
                .tonal-row {{ display: flex; align-items: center; margin-bottom: 12px; }}
                .tonal-label {{ width: 80px; font-size: 12px; font-weight: 600; color: #aaa; }}
                .tonal-track {{ flex: 1; height: 8px; background: #333; margin: 0 15px; display: flex; position: relative; }}
                .tonal-bar {{ height: 100%; border-radius: 4px; }}
                .tonal-value {{ width: 50px; text-align: right; font-family: monospace; font-weight: bold; }}
                
                /* Micro Metrics */
                .micro-val {{ font-size: 24px; font-weight: 800; margin-bottom: 4px; }}
                .micro-lab {{ font-size: 10px; text-transform: uppercase; color: #888; letter-spacing: 1px; }}

                /* Waveform */
                .wf-box {{ height: 100px; background: rgba(0,0,0,0.2); border-radius: 12px; margin-top: 10px; }}
                
                /* Evolution */
                .evo-flex {{ display: flex; justify-content: space-between; position: relative; padding: 20px 0; }}
                .evo-flex::after {{ content:''; position: absolute; top: 26px; left: 0; right: 0; height: 2px; background: #333; z-index: 1; }}
                .evo-node {{ text-align: center; z-index: 2; flex: 1; }}
                .evo-dot {{ width: 12px; height: 12px; border-radius: 50%; background: #444; margin: 0 auto 10px; border: 3px solid {bg_color}; }}
                .evo-label {{ font-size: 10px; color: #888; text-transform: uppercase; }}
                .evo-score {{ font-weight: bold; margin-top: 4px; }}
                
                /* Tabs */
                .tab-btn {{ background: transparent; border: 1px solid #444; color: #888; padding: 6px 16px; border-radius: 8px; cursor: pointer; }}
                .tab-btn.active {{ background: {accent}; color: {bg_color}; border-color: {accent}; font-weight: bold; }}
            </style>
        </head>
        <body>
            <div class="container">
                <header>
                    <div>
                        <div class="verdict-badge">{data['verdict']}</div>
                        <h1 style="margin: 8px 0 4px 0;">Mastering Audit</h1>
                        <div style="color: #888;">{data['filename']} &bull; {data['date']}</div>
                    </div>
                    <div class="health-gauge">
                        <div style="font-size: 10px; text-transform: uppercase; color: #888;">Health</div>
                        <div style="font-size: 32px; font-weight: 800; color: {score_color}">{data['health_score']}</div>
                    </div>
                </header>

                <div class="grid">
                    <div class="card">
                        <h2>Stereo Soundstage</h2>
                        <div class="stage">
                            <div class="arc high"></div>
                            <div class="arc mid"></div>
                            <div class="arc low"></div>
                            <div style="width: 20px; height: 20px; background: #555; border-radius: 50%; z-index: 10; margin-bottom: -10px;"></div>
                        </div>
                        <div style="display:flex; justify-content: space-around; margin-top: 20px; font-size: 11px; font-weight: bold; color: #666;">
                            <span>LOW: {m['band_corr']['low']:.2f}</span>
                            <span>MID: {m['band_corr']['mid']:.2f}</span>
                            <span>HIGH: {m['band_corr']['high']:.2f}</span>
                        </div>
                    </div>
                    
                    <div class="card">
                        <h2>Surgical Balance</h2>
                        {tonal_rows}
                    </div>
                </div>

                {micro_html}

                <div class="card">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                        <h2 style="margin: 0;">Dynamic Transformation</h2>
                        <div>
                            <button class="tab-btn active" onclick="toggleWf(this, 'master')">Mastered</button>
                            <button class="tab-btn" onclick="toggleWf(this, 'original')">Original</button>
                        </div>
                    </div>
                    <div class="wf-box" id="wf-container">
                        <svg width="100%" height="100%" viewBox="0 0 750 100" preserveAspectRatio="none">
                            <g id="wf-original" style="display:none">{make_waveform_svg(data['envelopes']['original'], '#444')}</g>
                            <g id="wf-master">{make_waveform_svg(data['envelopes']['master'], accent)}</g>
                        </svg>
                    </div>
                    <div style="display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 24px; text-align: center;">
                        <div><div style="color:#888; font-size:11px; text-transform:uppercase;">LUFS</div><div style="font-size:18px; font-weight:bold;">{m['lufs']:.1f}</div></div>
                        <div><div style="color:#888; font-size:11px; text-transform:uppercase;">Crest Factor</div><div style="font-size:18px; font-weight:bold;">{m['crest_factor']:.1f}dB</div></div>
                        <div><div style="color:#888; font-size:11px; text-transform:uppercase;">Peak</div><div style="font-size:18px; font-weight:bold;">{m['peak_db']:.1f}dB</div></div>
                    </div>
                </div>

                <div class="card">
                    <h2>The Journey</h2>
                    <div class="evo-flex">
                        {evolution_html}
                    </div>
                </div>

                <script>
                    function toggleWf(btn, type) {{
                        document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
                        btn.classList.add('active');
                        document.getElementById('wf-original').style.display = type === 'original' ? 'block' : 'none';
                        document.getElementById('wf-master').style.display = type === 'master' ? 'block' : 'none';
                    }}
                </script>
            </div>
        </body>
        </html>
        """
        with open(path, 'w') as f: f.write(html)

    def _calculate_health_score_simple(self, m):
        score = 100
        score -= min(20, abs(m['lufs'] - (-8.0)) * 2)
        if m['bass_corr'] < 0.9: score -= 15
        if m['ms_ratio'] < -12 or m['ms_ratio'] > -2: score -= 10
        slope = m.get('slope', -3.0)
        if slope < -5.0 or slope > -2.5: score -= 10
        return max(0, int(score))

    def _create_matplotlib_dashboard(self, data):
        m = data['metrics']
        bg_color, card_color, accent_color, text_color = "#131314", "#1e1f20", "#A8C7FA", "#e3e3e3"
        plt.rcParams.update({'text.color': text_color, 'axes.labelcolor': text_color, 'xtick.color': text_color, 'ytick.color': text_color})
        fig = plt.figure(figsize=(14, 16), facecolor=bg_color)
        grid = plt.GridSpec(5, 2, hspace=0.5, wspace=0.3)
        
        # Primary Elite Fidelity Score
        ax_score = fig.add_subplot(grid[0, 0], facecolor=bg_color); ax_score.axis('off')
        ax_score.text(0.5, 0.65, f"{data['overall_score']}", ha='center', va='center', fontsize=85, fontweight='bold', color="#FF00FF")
        ax_score.text(0.5, 0.35, "ELITE FIDELITY SCORE", ha='center', va='center', fontsize=14, color=text_color, alpha=0.8)
        ax_score.text(0.5, 0.15, f"Tech Health: {data['health_score']} | Texture: {data['coherence_score']}", ha='center', va='center', fontsize=11, color=text_color, alpha=0.6)
        
        # Key Technical Stats
        ax_metrics = fig.add_subplot(grid[0, 1], facecolor=bg_color); ax_metrics.axis('off')
        metrics_text = [
            f"Loudness:  {m['lufs']:.2f} LUFS", 
            f"True Peak: {m['peak_db']:.2f} dB", 
            f"Dyn Range: {m['plr']:.2f} dB", 
            f"Crest:     {m.get('crest_factor', 0):.1f} dB"
        ]
        for i, text in enumerate(metrics_text): 
            ax_metrics.text(0.1, 0.9 - (i * 0.2), text, fontsize=14, family='monospace', fontweight='bold')
        
        # Tonal Balance View
        ax_tonal = fig.add_subplot(grid[1:3, :], facecolor=card_color)
        bands = ["sub", "bass", "mud", "low_mid", "mid", "presence", "air", "sparkle"]
        values = [data['tonal_dev'].get(k, 0) for k in bands]
        ax_tonal.bar(bands, values, color=['#7ab3ef' if v < 0 else '#fbc02d' for v in values], alpha=0.8)
        ax_tonal.set_title("TONAL DEVIATION", fontweight='bold'); ax_tonal.grid(axis='y', linestyle='--', alpha=0.3)

        # Pro Fidelity Audit Chart
        ax_fid = fig.add_subplot(grid[3, 0], facecolor=bg_color)
        fid_labels = ['Translation', 'Punch', 'Cleanliness']
        fid_vals = [data['translation_score'], data['punch_score'], data['cleanliness_score']]
        ax_fid.barh(fid_labels, fid_vals, color=['#c4eed0', '#fff4a3', '#A8C7FA'], alpha=0.7)
        ax_fid.set_xlim(0, 100); ax_fid.set_title("PRO FIDELITY AUDIT", fontweight='bold'); ax_fid.grid(axis='x', linestyle=':', alpha=0.5)
        
        # Add penalty text to the audit section
        all_fid_p = data.get('translation_penalties', []) + data.get('punch_penalties', []) + data.get('cleanliness_penalties', [])
        if all_fid_p:
            p_text = "Deductions: " + " | ".join(all_fid_p[:3])
            if len(all_fid_p) > 3: p_text += "..."
            ax_fid.text(0, -0.8, p_text, fontsize=9, color="#f2b8b5", alpha=0.8)

        # Texture Coherence Chart
        if 'micro' in m:
            ax_micro = fig.add_subplot(grid[3, 1], facecolor=bg_color)
            mc = m['micro']
            labels = ['HF Sharpness', 'Phase Stability', 'Complexity', 'Sparkle %']
            v_sharp = min(10, mc.get('hf_sharpness', 0) / 2)
            v_phase = max(0, 10 - (mc.get('phase_drift', 0) * 100)) 
            v_complex = min(10, mc.get('spectral_complexity', 0))
            v_sparkle = min(10, mc.get('sparkle_energy', 0) * 5)
            vals = [v_sharp, v_phase, v_complex, v_sparkle]
            ax_micro.barh(labels, vals, color=accent_color, alpha=0.6)
            ax_micro.set_xlim(0, 10); ax_micro.set_title("HI-FI TEXTURE SCORE", fontweight='bold'); ax_micro.grid(axis='x', linestyle=':', alpha=0.5)

        return fig