#!/usr/bin/env python3
"""Generate the static site for Radio Susan from playlist.json.
Outputs to /var/www/radio/. Run after generate_daily_playlist.py.
"""

import grp
import json
import os
import sys
from datetime import datetime
from pathlib import Path

PLAYLIST_JSON = Path("/var/lib/radio/playlist.json")
OUTPUT_DIR = Path("/var/www/radio")
STREAM_URL = "https://radio.jihakuz.xyz/stream"


def set_mediaserver_perms(path):
    try:
        gid = grp.getgrnam("mediaserver").gr_gid
        os.chown(str(path), -1, gid)
        os.chmod(str(path), 0o664)
    except Exception:
        pass


def generate_html(playlist):
    generated = playlist["generated_at"][:10]
    total_tracks = playlist["total_tracks"]
    duration = playlist["total_duration_hours"]
    shows = playlist["shows"]
    entries = playlist["entries"]

    # Build tracks-only list for the schedule
    tracks = [e for e in entries if e["type"] == "track"]

    # Group tracks by show
    show_tracks = {}
    for t in tracks:
        show_name = t.get("show", "Unknown")
        show_tracks.setdefault(show_name, []).append(t)

    # Mode stats
    mode_counts = {}
    for t in tracks:
        m = t.get("mode", "unknown")
        mode_counts[m] = mode_counts.get(m, 0) + 1

    # Build show cards HTML
    show_cards = ""
    for show in shows:
        name = show["name"]
        trks = show_tracks.get(name, [])
        show_cards += f"""
        <div class="show-card" id="show-{name.lower().replace(' ', '-')}">
            <div class="show-header">
                <div class="show-time">{show['start']} — {show['end']}</div>
                <h2 class="show-name">{name}</h2>
                <div class="show-desc">{show['description']} · Energy {show['energy']} · {len(trks)} tracks</div>
            </div>
            <div class="show-tracklist">
                {''.join(f'<div class="track" data-start="{t["start_time"]}">'
                    f'<span class="track-time">{t["start_formatted"][:5]}</span>'
                    f'<span class="track-artist">{_esc(t["artist"])}</span>'
                    f'<span class="track-sep">—</span>'
                    f'<span class="track-title">{_esc(t["title"])}</span>'
                    f'<span class="track-meta">{_esc(t.get("album", ""))}</span>'
                    f'<span class="track-mode">{t["mode"]}</span>'
                    f'</div>' for t in trks)}
            </div>
        </div>
"""

    html = f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Radio Susan — 99.0</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}

        :root {{
            --bg: #0a0a0f;
            --surface: #12121a;
            --surface2: #1a1a26;
            --border: #2a2a3a;
            --text: #e0e0e8;
            --text-dim: #7a7a8e;
            --accent: #ff6b35;
            --accent2: #ffd700;
            --green: #4ade80;
            --red: #f87171;
        }}

        body {{
            font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
            background: var(--bg);
            color: var(--text);
            line-height: 1.6;
            min-height: 100vh;
        }}

        .container {{
            max-width: 900px;
            margin: 0 auto;
            padding: 2rem 1.5rem;
        }}

        /* Header */
        .header {{
            text-align: center;
            margin-bottom: 3rem;
            padding-bottom: 2rem;
            border-bottom: 1px solid var(--border);
        }}

        .header h1 {{
            font-size: 2.5rem;
            font-weight: 700;
            color: var(--accent);
            letter-spacing: 0.05em;
        }}

        .header .freq {{
            font-size: 1.2rem;
            color: var(--accent2);
            margin-top: 0.25rem;
        }}

        .header .meta {{
            font-size: 0.8rem;
            color: var(--text-dim);
            margin-top: 1rem;
        }}

        /* Now Playing */
        .now-playing {{
            background: var(--surface);
            border: 1px solid var(--accent);
            border-radius: 8px;
            padding: 1.5rem;
            margin-bottom: 2rem;
            text-align: center;
        }}

        .now-playing .label {{
            font-size: 0.7rem;
            text-transform: uppercase;
            letter-spacing: 0.2em;
            color: var(--accent);
            margin-bottom: 0.5rem;
        }}

        .now-playing .live-dot {{
            display: inline-block;
            width: 8px;
            height: 8px;
            background: var(--red);
            border-radius: 50%;
            margin-right: 0.5rem;
            animation: pulse 2s infinite;
        }}

        @keyframes pulse {{
            0%, 100% {{ opacity: 1; }}
            50% {{ opacity: 0.3; }}
        }}

        .now-playing .track-name {{
            font-size: 1.3rem;
            font-weight: 600;
            color: var(--text);
        }}

        .now-playing .track-album {{
            font-size: 0.85rem;
            color: var(--text-dim);
            margin-top: 0.25rem;
        }}

        .now-playing .show-label {{
            font-size: 0.75rem;
            color: var(--accent2);
            margin-top: 0.75rem;
        }}

        .listen-btn {{
            display: inline-block;
            margin-top: 1rem;
            padding: 0.6rem 2rem;
            background: var(--accent);
            color: var(--bg);
            text-decoration: none;
            border-radius: 4px;
            font-weight: 700;
            font-size: 0.85rem;
            letter-spacing: 0.05em;
            border: none;
            cursor: pointer;
        }}

        .listen-btn:hover {{
            background: #ff8555;
        }}

        /* Up Next */
        .up-next {{
            background: var(--surface);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 1.25rem;
            margin-bottom: 2.5rem;
        }}

        .up-next h3 {{
            font-size: 0.75rem;
            text-transform: uppercase;
            letter-spacing: 0.15em;
            color: var(--text-dim);
            margin-bottom: 0.75rem;
        }}

        .up-next .next-track {{
            display: flex;
            justify-content: space-between;
            padding: 0.3rem 0;
            font-size: 0.85rem;
        }}

        .up-next .next-time {{
            color: var(--text-dim);
            min-width: 50px;
        }}

        /* Stats bar */
        .stats {{
            display: flex;
            justify-content: space-around;
            background: var(--surface);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 1rem;
            margin-bottom: 2.5rem;
            font-size: 0.8rem;
        }}

        .stat {{
            text-align: center;
        }}

        .stat .stat-val {{
            font-size: 1.3rem;
            font-weight: 700;
            color: var(--accent);
        }}

        .stat .stat-label {{
            color: var(--text-dim);
            font-size: 0.7rem;
            text-transform: uppercase;
            letter-spacing: 0.1em;
        }}

        /* Show cards */
        .show-card {{
            background: var(--surface);
            border: 1px solid var(--border);
            border-radius: 8px;
            margin-bottom: 1.5rem;
            overflow: hidden;
        }}

        .show-header {{
            padding: 1.25rem;
            border-bottom: 1px solid var(--border);
            cursor: pointer;
        }}

        .show-time {{
            font-size: 0.7rem;
            color: var(--accent2);
            letter-spacing: 0.1em;
        }}

        .show-name {{
            font-size: 1.2rem;
            font-weight: 600;
            margin-top: 0.2rem;
        }}

        .show-desc {{
            font-size: 0.75rem;
            color: var(--text-dim);
            margin-top: 0.25rem;
        }}

        .show-tracklist {{
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
        }}

        .show-card.open .show-tracklist {{
            max-height: 5000px;
        }}

        .track {{
            display: flex;
            align-items: center;
            gap: 0.75rem;
            padding: 0.4rem 1.25rem;
            font-size: 0.8rem;
            border-bottom: 1px solid var(--bg);
        }}

        .track:hover {{
            background: var(--surface2);
        }}

        .track.active {{
            background: var(--surface2);
            border-left: 3px solid var(--accent);
        }}

        .track-time {{
            color: var(--text-dim);
            min-width: 40px;
            font-size: 0.75rem;
        }}

        .track-artist {{
            font-weight: 600;
            color: var(--text);
        }}

        .track-sep {{
            color: var(--text-dim);
        }}

        .track-title {{
            color: var(--text);
            flex: 1;
        }}

        .track-meta {{
            color: var(--text-dim);
            font-size: 0.7rem;
            max-width: 150px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }}

        .track-mode {{
            font-size: 0.6rem;
            padding: 0.15rem 0.4rem;
            border-radius: 3px;
            background: var(--surface2);
            color: var(--text-dim);
            white-space: nowrap;
        }}

        /* Footer */
        .footer {{
            text-align: center;
            padding: 2rem 0;
            margin-top: 2rem;
            border-top: 1px solid var(--border);
            color: var(--text-dim);
            font-size: 0.7rem;
        }}

        @media (max-width: 600px) {{
            .container {{ padding: 1rem; }}
            .header h1 {{ font-size: 1.8rem; }}
            .track-meta {{ display: none; }}
            .stats {{ flex-wrap: wrap; gap: 0.5rem; }}
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>RADIO SUSAN</h1>
            <div class="freq">99.0 FM</div>
            <div class="meta">Generated {generated} · {total_tracks} tracks · {duration}h</div>
        </div>

        <div class="now-playing" id="now-playing">
            <div class="label"><span class="live-dot"></span>NOW PLAYING</div>
            <div class="track-name" id="np-track">Loading...</div>
            <div class="track-album" id="np-album"></div>
            <div class="show-label" id="np-show"></div>
            <button class="listen-btn" onclick="togglePlay()">▶ LISTEN</button>
        </div>

        <div class="up-next" id="up-next">
            <h3>Up Next</h3>
            <div id="next-tracks"></div>
        </div>

        <div class="stats">
            <div class="stat"><div class="stat-val">{total_tracks}</div><div class="stat-label">Tracks</div></div>
            <div class="stat"><div class="stat-val">{len(shows)}</div><div class="stat-label">Shows</div></div>
            <div class="stat"><div class="stat-val">{mode_counts.get('full_album', 0)}</div><div class="stat-label">Album Tracks</div></div>
            <div class="stat"><div class="stat-val">{mode_counts.get('deep_cuts', 0)}</div><div class="stat-label">Deep Cuts</div></div>
            <div class="stat"><div class="stat-val">{mode_counts.get('new_to_library', 0)}</div><div class="stat-label">New</div></div>
        </div>

        <h2 style="font-size: 1rem; margin-bottom: 1rem; color: var(--text-dim); letter-spacing: 0.1em;">TODAY'S SCHEDULE</h2>

        {show_cards}

        <div class="footer">
            RADIO SUSAN · Powered by Liquidsoap + Icecast · Self-hosted on Susan
        </div>
    </div>

    <audio id="audio-player" preload="none">
        <source src="{STREAM_URL}" type="audio/mpeg">
    </audio>

    <script>
        const schedule = {json.dumps([e for e in entries if e['type'] == 'track'], separators=(',', ':'))};

        function getScheduleSeconds() {{
            const now = new Date();
            return now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
        }}

        // Find track in schedule by artist+title match
        function findInSchedule(artist, title) {{
            for (let i = 0; i < schedule.length; i++) {{
                if (schedule[i].artist === artist && schedule[i].title === title) {{
                    return {{ track: schedule[i], index: i }};
                }}
            }}
            return null;
        }}

        // Fallback: find by time
        function findByTime() {{
            const secs = getScheduleSeconds();
            let current = null;
            let idx = 0;
            for (let i = 0; i < schedule.length; i++) {{
                if (schedule[i].start_time <= secs) {{
                    current = schedule[i];
                    idx = i;
                }}
            }}
            return current ? {{ track: current, index: idx }} : null;
        }}

        let lastNp = '';

        async function updateNowPlaying() {{
            // Poll live state from liquidsoap
            let liveArtist = '', liveTitle = '';
            try {{
                const resp = await fetch('/now_playing.json?' + Date.now());
                if (resp.ok) {{
                    const data = await resp.json();
                    liveArtist = data.artist || '';
                    liveTitle = data.title || '';
                }}
            }} catch(e) {{}}

            const npKey = liveArtist + '|' + liveTitle;

            // Update now playing display
            if (liveArtist || liveTitle) {{
                document.getElementById('np-track').textContent =
                    (liveArtist && liveTitle) ? liveArtist + ' \u2014 ' + liveTitle :
                    liveArtist || liveTitle;
            }}

            // Try to find this track in the schedule for metadata + up next
            let match = null;
            if (liveArtist && liveTitle) {{
                match = findInSchedule(liveArtist, liveTitle);
            }}
            if (!match) {{
                match = findByTime();
            }}

            if (match) {{
                const {{ track, index }} = match;
                document.getElementById('np-album').textContent = track.album || '';
                document.getElementById('np-show').textContent = track.show + ' \u00b7 ' + track.mode;

                // Up next (from schedule position)
                const nextDiv = document.getElementById('next-tracks');
                nextDiv.innerHTML = '';
                for (let i = index + 1; i < Math.min(index + 4, schedule.length); i++) {{
                    const t = schedule[i];
                    const div = document.createElement('div');
                    div.className = 'next-track';
                    div.innerHTML = '<span class="next-time">' + t.start_formatted.slice(0, 5) + '</span> '
                        + '<span>' + t.artist + ' \u2014 ' + t.title + '</span>';
                    nextDiv.appendChild(div);
                }}

                // Highlight active track
                if (npKey !== lastNp) {{
                    document.querySelectorAll('.track.active').forEach(el => el.classList.remove('active'));
                    const allTracks = document.querySelectorAll('.track');
                    allTracks.forEach(el => {{
                        if (parseFloat(el.dataset.start) === track.start_time) {{
                            el.classList.add('active');
                            const card = el.closest('.show-card');
                            if (card && !card.classList.contains('open')) {{
                                card.classList.add('open');
                            }}
                            el.scrollIntoView({{ behavior: 'smooth', block: 'center' }});
                        }}
                    }});
                    lastNp = npKey;
                }}
            }} else {{
                document.getElementById('np-album').textContent = '';
                document.getElementById('np-show').textContent = '';
            }}
        }}

        // Toggle show tracklists
        document.querySelectorAll('.show-header').forEach(header => {{
            header.addEventListener('click', () => {{
                header.parentElement.classList.toggle('open');
            }});
        }});

        // Audio player
        let playing = false;
        function togglePlay() {{
            const audio = document.getElementById('audio-player');
            const btn = document.querySelector('.listen-btn');
            if (playing) {{
                audio.pause();
                audio.src = '';
                btn.textContent = '\u25b6 LISTEN';
                playing = false;
            }} else {{
                audio.src = '{STREAM_URL}';
                audio.play();
                btn.textContent = '\u23f8 STOP';
                playing = true;
            }}
        }}

        // Update every 10 seconds
        updateNowPlaying();
        setInterval(updateNowPlaying, 10000);

        // Open current show by default
        const timeMatch = findByTime();
        if (timeMatch) {{
            const showId = 'show-' + timeMatch.track.show.toLowerCase().replace(/ /g, '-');
            const el = document.getElementById(showId);
            if (el) el.classList.add('open');
        }}
    </script>
</body>
</html>"""

    return html


def _esc(s):
    """Escape HTML entities."""
    return (s or "").replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;")


def main():
    if not PLAYLIST_JSON.exists():
        print(f"ERROR: {PLAYLIST_JSON} not found. Run generate_daily_playlist.py first.")
        sys.exit(1)

    playlist = json.load(open(PLAYLIST_JSON))
    print(f"Generating site from playlist ({playlist['total_tracks']} tracks)...")

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    # Generate index.html
    html = generate_html(playlist)
    index_path = OUTPUT_DIR / "index.html"
    index_path.write_text(html)
    set_mediaserver_perms(index_path)

    # Copy playlist.json for API access
    api_path = OUTPUT_DIR / "playlist.json"
    api_path.write_text(json.dumps(playlist, separators=(",", ":")))
    set_mediaserver_perms(api_path)

    print(f"Site generated at {OUTPUT_DIR}")
    print(f"  index.html: {index_path.stat().st_size / 1024:.1f}KB")
    print(f"  playlist.json: {api_path.stat().st_size / 1024:.1f}KB")


if __name__ == "__main__":
    main()
