#!/usr/bin/env python3
"""
Prepare HyperFrames project for preview via `hyperframes play`.

Creates an index.html symlink to the composition HTML so that
`hyperframes play <dir>` can serve it through the built-in
<hyperframes-player> web component. No player HTML is injected
into the composition — the composition stays pure for rendering.

Also auto-fixes <audio> elements missing id attributes.

Usage:
    python3 scripts/preview-gen.py \\
        --input hyperframes-output/<name>.html \\
        --output hyperframes-output/
"""
import argparse
import os
import pathlib
import re
import sys
import uuid


def extract_composition_id(html):
    """Extract composition-id from HTML if not provided."""
    m = re.search(r'data-composition-id\s*=\s*"([^"]+)"', html)
    return m.group(1) if m else "unknown-composition"


def extract_scene_info(html):
    """Extract scene start times from audio clips."""
    starts = set()
    for m in re.finditer(r'data-start\s*=\s*"([^"]+)"', html):
        try:
            starts.add(float(m.group(1)))
        except ValueError:
            pass
    return sorted(starts)


def extract_dimensions(html):
    """Extract width, height, and duration from composition root."""
    w = re.search(r'data-width\s*=\s*"(\d+)"', html)
    h = re.search(r'data-height\s*=\s*"(\d+)"', html)
    d = re.search(r'data-duration\s*=\s*"([^"]+)"', html)
    return {
        'width': int(w.group(1)) if w else 1920,
        'height': int(h.group(1)) if h else 1080,
        'duration': float(d.group(1)) if d else 30,
    }


def fix_audio_ids(html):
    """Add missing id attributes to <audio> elements (required by renderer)."""
    def _add_id(match):
        tag = match.group(0)
        if 'id=' in tag:
            return tag
        src_m = re.search(r'src\s*=\s*"([^"]+)"', tag)
        if src_m:
            fname = os.path.basename(src_m.group(1))
            base = os.path.splitext(fname)[0]
            audio_id = f"audio-{base}"
        else:
            audio_id = f"audio-{uuid.uuid4().hex[:8]}"
        return tag.replace('<audio', f'<audio id="{audio_id}"', 1)

    fixed = re.sub(r'<audio\b[^>]*>', _add_id, html)
    added = len(re.findall(r'<audio\b[^>]*>', fixed)) - len(re.findall(r'id="audio-', html))
    if added > 0:
        print(f"  Audio fix: added id to {added} <audio> element(s)")
    return fixed


def setup_project(input_path, output_dir):
    """Prepare output directory for hyperframes play.

    Fixes audio ids in the source HTML and creates an index.html
    symlink in the output directory. The composition stays pure —
    HyperFrames' built-in <hyperframes-player> handles all UI.
    """
    input_path = os.path.abspath(input_path)
    output_dir = os.path.abspath(output_dir)
    os.makedirs(output_dir, exist_ok=True)

    with open(input_path, 'r') as f:
        html = f.read()

    comp_id = extract_composition_id(html)
    if comp_id == "unknown-composition":
        print(f"ERROR: No data-composition-id found in {input_path}", file=sys.stderr)
        sys.exit(1)

    dims = extract_dimensions(html)

    # Fix audio ids in the source HTML
    html = fix_audio_ids(html)
    with open(input_path, 'w') as f:
        f.write(html)

    # Create index.html symlink
    index_path = os.path.join(output_dir, "index.html")
    input_rel = os.path.relpath(input_path, output_dir)
    if os.path.islink(index_path) or os.path.exists(index_path):
        os.unlink(index_path)
    os.symlink(input_rel, index_path)

    scenes = extract_scene_info(html)
    scenes_str = ",".join(str(s) for s in scenes) if scenes else "0"

    print(f"  Composition: {comp_id}")
    print(f"  Dimensions: {dims['width']}x{dims['height']}, {dims['duration']}s")
    print(f"  Scenes: {scenes_str}")
    print(f"  Index: {index_path} -> {input_rel}")
    print(f"")
    print(f"  Ready for preview. Run:")
    print(f"    hyperframes play {output_dir}")
    return True


PREVIEW_HTML_TEMPLATE = """<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width={width}, height={height}" />
<title>{title}</title>
<style>
  body {{ margin: 0; background: #000; display: flex; justify-content: center;
        align-items: center; min-height: 100vh; }}
  hyperframes-player {{ width: 100%; max-width: {width}px; aspect-ratio: {width}/{height}; }}
</style>
</head>
<body>
<script type="module" src="https://cdn.jsdelivr.net/npm/@hyperframes/player"></script>
<hyperframes-player src="{src}" controls autoplay></hyperframes-player>
</body>
</html>"""


def generate_preview_html(composition_path, output_dir, dims, title):
    """Generate a standalone preview HTML using @hyperframes/player CDN."""
    src = os.path.relpath(composition_path, output_dir)
    html = PREVIEW_HTML_TEMPLATE.format(
        width=dims['width'],
        height=dims['height'],
        title=title or os.path.basename(composition_path),
        src=src,
    )
    preview_path = os.path.join(output_dir, "preview.html")
    with open(preview_path, 'w') as f:
        f.write(html)
    print(f"  Preview HTML: {preview_path}")
    return preview_path


def main():
    parser = argparse.ArgumentParser(
        description="Prepare project for hyperframes play preview"
    )
    parser.add_argument("--input", required=True, help="Path to composition HTML file")
    parser.add_argument("--output", required=True, help="Output directory")
    parser.add_argument("--preview-html", action="store_true",
                        help="Generate standalone preview.html with CDN player")
    args = parser.parse_args()

    setup_project(args.input, args.output)

    if args.preview_html:
        with open(args.input) as f:
            dims = extract_dimensions(f.read())
        title = os.path.splitext(os.path.basename(args.input))[0]
        generate_preview_html(args.input, args.output, dims, title)


if __name__ == "__main__":
    main()
