"""
Preflight dashboard: serves audio files and transcription results for human evaluation.
Run: python preflight/dashboard.py
Then open http://localhost:8765
"""
import json
import os
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
from urllib.parse import unquote, parse_qs, urlparse

PREFLIGHT_DIR = Path(__file__).parent
RESULTS_DIR = PREFLIGHT_DIR / "results"
SEGMENTS_DIR = PREFLIGHT_DIR / "pF_BQpHaIdU" / "segments"
PORT = 8765


def load_results():
    phases = {}
    for name in ["phase1_single", "phase2_concurrent", "phase3_full"]:
        p = RESULTS_DIR / f"{name}.json"
        if p.exists():
            phases[name] = json.loads(p.read_text())
    combined = RESULTS_DIR / "combined_summary.json"
    summary = json.loads(combined.read_text()) if combined.exists() else {}
    return phases, summary


def build_dashboard_html():
    phases, summary = load_results()

    # Build segments table from the largest phase available
    best_phase = None
    for name in ["phase3_full", "phase2_concurrent", "phase1_single"]:
        if name in phases and phases[name].get("results"):
            best_phase = phases[name]
            break

    results = best_phase.get("results", []) if best_phase else []
    phase_summary = best_phase.get("summary", {}) if best_phase else {}

    # Compute aggregates
    total = len(results)
    success = sum(1 for r in results if r.get("status") == "success")
    errors = sum(1 for r in results if r.get("status") != "success")
    avg_quality = 0
    quality_scores = [r["validation"]["quality_score"] for r in results if "validation" in r]
    if quality_scores:
        avg_quality = sum(quality_scores) / len(quality_scores)

    tts_clean = sum(1 for r in results if r.get("validation", {}).get("tts_clean_eligible"))
    asr_ok = sum(1 for r in results if r.get("validation", {}).get("asr_eligible"))
    no_speech = sum(1 for r in results if r.get("validation", {}).get("is_no_speech"))
    cache_hits = sum(1 for r in results if r.get("token_usage", {}).get("cache_hit"))
    total_tokens = sum(r.get("token_usage", {}).get("input", 0) + r.get("token_usage", {}).get("output", 0) for r in results)
    latencies = [r["latency_ms"] for r in results if r.get("latency_ms", 0) > 0]
    avg_latency = sum(latencies) / len(latencies) if latencies else 0

    # Quality distribution
    q_buckets = {"0.0-0.3": 0, "0.3-0.5": 0, "0.5-0.7": 0, "0.7-0.9": 0, "0.9-1.0": 0}
    for q in quality_scores:
        if q < 0.3: q_buckets["0.0-0.3"] += 1
        elif q < 0.5: q_buckets["0.3-0.5"] += 1
        elif q < 0.7: q_buckets["0.5-0.7"] += 1
        elif q < 0.9: q_buckets["0.7-0.9"] += 1
        else: q_buckets["0.9-1.0"] += 1

    # Phase comparison
    phase_rows = ""
    for pname in ["phase1_single", "phase2_concurrent", "phase3_full"]:
        if pname in phases:
            s = phases[pname].get("summary", {})
            phase_rows += f"""<tr>
                <td>{pname.replace('_', ' ').title()}</td>
                <td>{s.get('requests_sent', 0)}</td>
                <td>{s.get('responses_success', 0)}</td>
                <td>{s.get('responses_error', 0)}</td>
                <td>{s.get('responses_429', 0)}</td>
                <td>{s.get('avg_quality_score', 0):.3f}</td>
                <td>{s.get('avg_latency_ms', 0):.0f}ms</td>
                <td>{s.get('cache_hits', 0)}</td>
                <td>{s.get('total_time_s', 0):.1f}s</td>
            </tr>"""

    # Segments table rows
    seg_rows = ""
    for i, r in enumerate(results):
        if r.get("status") != "success":
            seg_rows += f"""<tr class="error-row">
                <td>{i+1}</td><td>{r['segment_id']}</td><td>{r.get('audio_duration_s',0):.1f}s</td>
                <td colspan="5" class="error">ERROR: {r.get('error_message','Unknown')}</td>
                <td>-</td><td>-</td></tr>"""
            continue

        v = r.get("validation", {})
        speaker = r.get("speaker", {})
        quality = v.get("quality_score", 0)
        q_class = "q-high" if quality >= 0.9 else "q-mid" if quality >= 0.7 else "q-low"
        lang = r.get("detected_language", "?")
        lang_class = "lang-match" if lang == "te" else "lang-mismatch"

        seg_rows += f"""<tr data-idx="{i}" onclick="selectSegment({i})">
            <td>{i+1}</td>
            <td class="seg-id">{r['segment_id']}</td>
            <td>{r.get('audio_duration_s',0):.1f}s</td>
            <td class="{q_class}">{quality:.3f}</td>
            <td class="{lang_class}">{lang}</td>
            <td>{speaker.get('emotion','')}</td>
            <td>{speaker.get('pace','')}</td>
            <td>{'Y' if v.get('tts_clean_eligible') else 'N'}</td>
            <td>{r.get('latency_ms',0):.0f}ms</td>
            <td>{v.get('num_event_tags',0)}</td>
        </tr>"""

    # Results as JSON for JS
    results_json = json.dumps(results, ensure_ascii=False)

    return f"""<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Preflight Dashboard - pF_BQpHaIdU</title>
<style>
*{{margin:0;padding:0;box-sizing:border-box}}
body{{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0f0f0f;color:#e0e0e0}}
.header{{background:#1a1a2e;padding:20px 30px;border-bottom:2px solid #16213e}}
.header h1{{font-size:1.5rem;color:#e94560}}
.header .subtitle{{color:#888;font-size:0.9rem;margin-top:4px}}
.stats-grid{{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;padding:20px 30px}}
.stat-card{{background:#1a1a2e;border-radius:10px;padding:16px;text-align:center;border:1px solid #16213e}}
.stat-card .value{{font-size:1.8rem;font-weight:700;color:#e94560}}
.stat-card .label{{font-size:0.75rem;color:#888;margin-top:4px;text-transform:uppercase;letter-spacing:1px}}
.stat-card.green .value{{color:#00b894}}
.stat-card.blue .value{{color:#0984e3}}
.stat-card.orange .value{{color:#fdcb6e}}
.section{{padding:20px 30px}}
.section h2{{font-size:1.1rem;color:#e94560;margin-bottom:12px;border-bottom:1px solid #222;padding-bottom:6px}}
table{{width:100%;border-collapse:collapse;font-size:0.85rem}}
th{{background:#16213e;padding:8px 10px;text-align:left;position:sticky;top:0;z-index:10}}
td{{padding:6px 10px;border-bottom:1px solid #1a1a2e}}
tr:hover{{background:#16213e;cursor:pointer}}
.error-row{{background:#2d1b1b}}
.error{{color:#e74c3c}}
.q-high{{color:#00b894;font-weight:700}}
.q-mid{{color:#fdcb6e}}
.q-low{{color:#e74c3c;font-weight:700}}
.lang-match{{color:#00b894}}
.lang-mismatch{{color:#e74c3c;font-weight:700}}
.detail-panel{{position:fixed;right:0;top:0;width:450px;height:100vh;background:#1a1a2e;
    border-left:2px solid #e94560;padding:20px;overflow-y:auto;transform:translateX(100%);
    transition:transform 0.3s;z-index:100}}
.detail-panel.open{{transform:translateX(0)}}
.detail-panel .close{{position:absolute;top:10px;right:15px;cursor:pointer;font-size:1.5rem;color:#e94560}}
.detail-panel h3{{color:#e94560;margin-bottom:12px}}
.detail-panel audio{{width:100%;margin:10px 0}}
.detail-panel .transcript{{background:#0f0f0f;padding:12px;border-radius:8px;margin:10px 0;
    font-size:1rem;line-height:1.6;white-space:pre-wrap;border:1px solid #333}}
.detail-panel .meta-grid{{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:10px 0}}
.detail-panel .meta-item{{background:#0f0f0f;padding:8px;border-radius:6px}}
.detail-panel .meta-item .mk{{font-size:0.7rem;color:#888;text-transform:uppercase}}
.detail-panel .meta-item .mv{{font-size:0.95rem;margin-top:2px}}
.segments-container{{max-height:60vh;overflow-y:auto}}
.filter-bar{{display:flex;gap:10px;margin-bottom:10px;flex-wrap:wrap}}
.filter-bar select,.filter-bar input{{background:#0f0f0f;color:#e0e0e0;border:1px solid #333;padding:6px 10px;border-radius:6px}}
</style></head><body>
<div class="header">
    <h1>Preflight Dashboard</h1>
    <div class="subtitle">Video: pF_BQpHaIdU — "Genius Behind Parle-G, Melody, Kismi..." — Telugu Podcast — {total} segments</div>
</div>

<div class="stats-grid">
    <div class="stat-card green"><div class="value">{success}/{total}</div><div class="label">Success Rate</div></div>
    <div class="stat-card"><div class="value">{avg_quality:.3f}</div><div class="label">Avg Quality</div></div>
    <div class="stat-card blue"><div class="value">{tts_clean}</div><div class="label">TTS Clean</div></div>
    <div class="stat-card green"><div class="value">{asr_ok}</div><div class="label">ASR Eligible</div></div>
    <div class="stat-card orange"><div class="value">{avg_latency:.0f}ms</div><div class="label">Avg Latency</div></div>
    <div class="stat-card blue"><div class="value">{cache_hits}</div><div class="label">Cache Hits</div></div>
    <div class="stat-card"><div class="value">{total_tokens:,}</div><div class="label">Total Tokens</div></div>
    <div class="stat-card orange"><div class="value">{no_speech}</div><div class="label">No Speech</div></div>
</div>

<div class="section">
    <h2>Phase Comparison</h2>
    <table><thead><tr><th>Phase</th><th>Sent</th><th>OK</th><th>Err</th><th>429</th><th>Quality</th><th>Latency</th><th>Cache</th><th>Time</th></tr></thead>
    <tbody>{phase_rows}</tbody></table>
</div>

<div class="section">
    <h2>Quality Distribution</h2>
    <div style="display:flex;gap:10px;margin-bottom:20px">
        {"".join(f'<div class="stat-card" style="flex:1"><div class="value">{v}</div><div class="label">{k}</div></div>' for k,v in q_buckets.items())}
    </div>
</div>

<div class="section">
    <h2>Segments (click to inspect)</h2>
    <div class="filter-bar">
        <select id="filterQuality" onchange="filterTable()">
            <option value="">All Qualities</option>
            <option value="high">High (≥0.9)</option>
            <option value="mid">Mid (0.7-0.9)</option>
            <option value="low">Low (<0.7)</option>
        </select>
        <select id="filterLang" onchange="filterTable()">
            <option value="">All Languages</option>
            <option value="te">Telugu</option>
            <option value="other">Other</option>
        </select>
        <input type="text" id="searchBox" placeholder="Search transcription..." oninput="filterTable()">
    </div>
    <div class="segments-container">
    <table id="segTable"><thead><tr>
        <th>#</th><th>Segment</th><th>Dur</th><th>Quality</th><th>Lang</th><th>Emotion</th><th>Pace</th><th>TTS</th><th>Latency</th><th>Tags</th>
    </tr></thead><tbody>{seg_rows}</tbody></table>
    </div>
</div>

<div class="detail-panel" id="detailPanel">
    <span class="close" onclick="closeDetail()">&times;</span>
    <h3 id="detailTitle">Segment Details</h3>
    <audio id="audioPlayer" controls></audio>
    <div class="transcript" id="transcriptBox"></div>
    <div class="transcript" id="taggedBox" style="color:#fdcb6e;font-size:0.9rem"></div>
    <div class="meta-grid" id="metaGrid"></div>
</div>

<script>
const results = {results_json};
function selectSegment(idx) {{
    const r = results[idx];
    if (!r) return;
    document.getElementById('detailPanel').classList.add('open');
    document.getElementById('detailTitle').textContent = r.segment_id;
    document.getElementById('audioPlayer').src = '/audio/' + r.original_file;
    document.getElementById('transcriptBox').textContent = r.transcription || '(no transcription)';
    document.getElementById('taggedBox').textContent = r.tagged || '';
    const v = r.validation || {{}};
    const s = r.speaker || {{}};
    const t = r.token_usage || {{}};
    let meta = `
        <div class="meta-item"><div class="mk">Quality Score</div><div class="mv">${{v.quality_score?.toFixed(3) || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Detected Language</div><div class="mv">${{r.detected_language || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Emotion</div><div class="mv">${{s.emotion || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Style</div><div class="mv">${{s.speaking_style || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Pace</div><div class="mv">${{s.pace || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Accent</div><div class="mv">${{s.accent || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Duration</div><div class="mv">${{r.audio_duration_s?.toFixed(1)}}s</div></div>
        <div class="meta-item"><div class="mk">Latency</div><div class="mv">${{r.latency_ms?.toFixed(0)}}ms</div></div>
        <div class="meta-item"><div class="mk">ASR Eligible</div><div class="mv">${{v.asr_eligible ? 'Yes' : 'No'}}</div></div>
        <div class="meta-item"><div class="mk">TTS Clean</div><div class="mv">${{v.tts_clean_eligible ? 'Yes' : 'No'}}</div></div>
        <div class="meta-item"><div class="mk">Chars/sec</div><div class="mv">${{v.chars_per_second?.toFixed(1) || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Boundary</div><div class="mv">${{v.boundary_score?.toFixed(2) || '-'}}</div></div>
        <div class="meta-item"><div class="mk">Tokens In</div><div class="mv">${{t.input || 0}}</div></div>
        <div class="meta-item"><div class="mk">Tokens Out</div><div class="mv">${{t.output || 0}}</div></div>
        <div class="meta-item"><div class="mk">Cache Hit</div><div class="mv">${{t.cache_hit ? 'Yes' : 'No'}}</div></div>
        <div class="meta-item"><div class="mk">Event Tags</div><div class="mv">${{v.num_event_tags || 0}}</div></div>
    `;
    if (v.flags && v.flags.length > 0) {{
        meta += `<div class="meta-item" style="grid-column:1/-1"><div class="mk">Flags</div><div class="mv" style="color:#e74c3c">${{v.flags.join(', ')}}</div></div>`;
    }}
    document.getElementById('metaGrid').innerHTML = meta;
}}
function closeDetail() {{ document.getElementById('detailPanel').classList.remove('open'); }}
function filterTable() {{
    const q = document.getElementById('filterQuality').value;
    const l = document.getElementById('filterLang').value;
    const s = document.getElementById('searchBox').value.toLowerCase();
    document.querySelectorAll('#segTable tbody tr').forEach((tr, i) => {{
        const r = results[i]; if (!r) return;
        let show = true;
        const qs = r.validation?.quality_score || 0;
        if (q === 'high' && qs < 0.9) show = false;
        if (q === 'mid' && (qs < 0.7 || qs >= 0.9)) show = false;
        if (q === 'low' && qs >= 0.7) show = false;
        if (l === 'te' && r.detected_language !== 'te') show = false;
        if (l === 'other' && r.detected_language === 'te') show = false;
        if (s && !(r.transcription || '').toLowerCase().includes(s)) show = false;
        tr.style.display = show ? '' : 'none';
    }});
}}
document.addEventListener('keydown', e => {{ if (e.key === 'Escape') closeDetail(); }});
</script></body></html>"""


class DashboardHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        parsed = urlparse(self.path)
        path = unquote(parsed.path)

        if path == "/" or path == "/index.html":
            html = build_dashboard_html()
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(html.encode())
            return

        if path.startswith("/audio/"):
            filename = path[7:]
            filepath = SEGMENTS_DIR / filename
            if filepath.exists():
                self.send_response(200)
                self.send_header("Content-Type", "audio/flac")
                self.send_header("Content-Length", str(filepath.stat().st_size))
                self.end_headers()
                self.wfile.write(filepath.read_bytes())
                return
            self.send_error(404)
            return

        if path == "/api/results":
            phases, summary = load_results()
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"phases": {k: v.get("summary") for k, v in phases.items()}, "summary": summary}, ensure_ascii=False).encode())
            return

        self.send_error(404)

    def log_message(self, format, *args):
        pass


def main():
    print(f"Starting preflight dashboard on http://localhost:{PORT}")
    print(f"Results dir: {RESULTS_DIR}")
    print(f"Segments dir: {SEGMENTS_DIR}")
    server = HTTPServer(("0.0.0.0", PORT), DashboardHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nShutdown.")


if __name__ == "__main__":
    main()
