#!/usr/bin/env python3
"""
Reveal.js HTML Slide Generator
Creates a self-contained, beautiful HTML presentation from slide outline YAML.
No internet required to view. Speaker notes mode: press S.
"""

import argparse
import os
import sys

try:
    import yaml
except ImportError:
    import subprocess
    subprocess.run([sys.executable, "-m", "pip", "install", "pyyaml", "-q"])
    import yaml

REVEAL_CDN = "https://cdn.jsdelivr.net/npm/reveal.js@5.1.0"

THEME_CSS = """
:root {
  --r-background-color: #0f0f1a;
  --r-main-color: #e8e8f0;
  --r-heading-color: #ffffff;
  --r-link-color: #3b82f6;
  --r-heading-font: 'Inter', 'Google Sans', 'Helvetica Neue', sans-serif;
  --r-main-font: 'Inter', 'Google Sans', 'Helvetica Neue', sans-serif;
  --r-heading-font-weight: 700;
  --r-heading-text-transform: none;
  --r-heading-letter-spacing: -0.02em;
  --accent: #3b82f6;
  --accent2: #0fc8a5;
  --text-muted: rgba(255,255,255,0.5);
}

.reveal .slides { text-align: left; }
.reveal h1 { font-size: 2.4em; line-height: 1.1; }
.reveal h2 { font-size: 1.7em; border-bottom: 2px solid var(--accent); padding-bottom: 0.2em; margin-bottom: 0.6em; }
.reveal h3 { font-size: 1.2em; color: var(--accent); }
.reveal ul, .reveal ol { margin-left: 1.5em; }
.reveal ul li { list-style: none; position: relative; padding-left: 1.4em; margin-bottom: 0.5em; line-height: 1.5; }
.reveal ul li::before { content: '→'; position: absolute; left: 0; color: var(--accent); }
.reveal .data-point {
  background: linear-gradient(135deg, rgba(59,130,246,0.15), rgba(15,200,165,0.10));
  border-left: 3px solid var(--accent);
  padding: 0.8em 1.2em;
  margin-top: 1.2em;
  border-radius: 4px;
  font-size: 0.95em;
  color: var(--accent2);
  font-weight: 600;
}
.reveal .visual-desc {
  color: var(--text-muted);
  font-size: 0.75em;
  font-style: italic;
  margin-top: 0.8em;
}
.reveal .slide-title-block { text-align: center; padding-top: 1em; }
.reveal .slide-title-block h1 { font-size: 2.6em; }
.reveal .slide-title-block .byline { font-size: 0.9em; color: var(--text-muted); margin-top: 1.2em; }
.reveal .slide-title-block .affiliation { font-size: 0.8em; color: var(--accent); }
.reveal .transition-slide { text-align: center; display: flex; align-items: center; justify-content: center; }
.reveal .transition-slide h2 { border: none; font-size: 2.2em; color: var(--accent2); }
.reveal .comparison-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2em; margin-top: 0.5em; }
.reveal .comparison-col h3 { font-size: 1em; margin-bottom: 0.5em; }
.reveal .quote-block { border-left: 4px solid var(--accent); padding: 1em 1.5em; background: rgba(59,130,246,0.05); margin: 1em 0; }
.reveal .quote-block p { font-size: 1.1em; font-style: italic; }
.reveal .progress { background: rgba(59,130,246,0.3); }
.reveal .progress span { background: var(--accent); }
.reveal .controls { color: var(--accent); }
.reveal .slide-number { color: var(--text-muted); font-size: 0.7em; }
"""


def slide_to_html(slide: dict, index: int, total: int) -> str:
    """Convert a single slide dict to Reveal.js HTML section."""
    slide_type = slide.get('type', 'content')
    title = slide.get('title', '')
    bullets = slide.get('bullets', [])
    data_point = slide.get('data_point', '')
    visual = slide.get('visual', '')
    speaker_notes = slide.get('speaker_notes', '')

    # Speaker notes section
    notes_html = ""
    if speaker_notes:
        notes_clean = str(speaker_notes).strip().replace('<', '&lt;').replace('>', '&gt;')
        notes_html = f'\n    <aside class="notes">{notes_clean}</aside>'

    if slide_type == 'title':
        subtitle = slide.get('subtitle', '')
        return f"""    <section data-background-color="#0d0d1f" data-transition="fade">
      <div class="slide-title-block">
        <h1>{title}</h1>
        {'<p class="byline">' + subtitle + '</p>' if subtitle else ''}
        {'<p class="affiliation">' + slide.get('affiliation', '') + '</p>' if slide.get('affiliation') else ''}
      </div>{notes_html}
    </section>"""

    elif slide_type == 'transition':
        return f"""    <section data-background-color="#0a1628" data-transition="zoom">
      <div class="transition-slide">
        <h2>{title}</h2>
      </div>{notes_html}
    </section>"""

    elif slide_type == 'quote':
        quote = bullets[0] if bullets else ''
        attribution = bullets[1] if len(bullets) > 1 else ''
        return f"""    <section data-transition="slide">
      <h2>{title}</h2>
      <div class="quote-block">
        <p>"{quote}"</p>
        {'<p style="text-align:right;font-size:0.85em;color:var(--text-muted);font-style:normal">— ' + attribution + '</p>' if attribution else ''}
      </div>
      {'<div class="visual-desc">' + visual + '</div>' if visual else ''}{notes_html}
    </section>"""

    elif slide_type == 'comparison':
        mid = len(bullets) // 2
        left = bullets[:mid]
        right = bullets[mid:]
        left_title = slide.get('left_title', 'Before')
        right_title = slide.get('right_title', 'After')
        left_html = '\n'.join(f'<li>{b}</li>' for b in left)
        right_html = '\n'.join(f'<li>{b}</li>' for b in right)
        return f"""    <section data-transition="slide">
      <h2>{title}</h2>
      <div class="comparison-grid">
        <div class="comparison-col">
          <h3>{left_title}</h3>
          <ul>{left_html}</ul>
        </div>
        <div class="comparison-col">
          <h3>{right_title}</h3>
          <ul>{right_html}</ul>
        </div>
      </div>
      {'<div class="data-point">' + data_point + '</div>' if data_point else ''}{notes_html}
    </section>"""

    else:  # content, data, image
        bullets_html = '\n'.join(
            f'          <li class="fragment">{b}</li>' for b in bullets
        ) if bullets else ''

        return f"""    <section data-transition="slide">
      <h2>{title}</h2>
      {'<ul>' + bullets_html + '</ul>' if bullets_html else ''}
      {'<div class="data-point">' + data_point + '</div>' if data_point else ''}
      {'<div class="visual-desc">💡 ' + visual + '</div>' if visual else ''}{notes_html}
    </section>"""


def generate_reveal(outline_path: str, output_dir: str) -> str:
    """Generate a complete Reveal.js presentation."""
    with open(outline_path) as f:
        outline = yaml.safe_load(f)

    deck = outline.get('deck', {})
    slides_data = outline.get('slides', [])
    title = deck.get('title', 'Presentation')

    sections = []
    for i, slide in enumerate(slides_data):
        sections.append(slide_to_html(slide, i + 1, len(slides_data)))

    slides_html = '\n\n'.join(sections)

    html = f"""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{title}</title>
  <link rel="stylesheet" href="{REVEAL_CDN}/dist/reveal.css">
  <link rel="stylesheet" href="{REVEAL_CDN}/dist/theme/black.css">
  <style>
{THEME_CSS}
  </style>
</head>
<body>
  <div class="reveal">
    <div class="slides">

{slides_html}

    </div>
  </div>
  <script src="{REVEAL_CDN}/dist/reveal.js"></script>
  <script src="{REVEAL_CDN}/plugin/notes/notes.js"></script>
  <script src="{REVEAL_CDN}/plugin/highlight/highlight.js"></script>
  <script>
    Reveal.initialize({{
      hash: true,
      slideNumber: 'c/t',
      progress: true,
      controls: true,
      transition: 'slide',
      backgroundTransition: 'fade',
      plugins: [ RevealNotes, RevealHighlight ],
      width: 1280,
      height: 720,
    }});
  </script>
</body>
</html>"""

    os.makedirs(output_dir, exist_ok=True)
    output_path = os.path.join(output_dir, "index.html")
    with open(output_path, 'w') as f:
        f.write(html)

    print(f"✅ Reveal.js presentation saved: {output_path}")
    print(f"   Open in browser to present")
    print(f"   Press S for speaker notes mode")
    print(f"   Press F for fullscreen")
    print(f"   Slides: {len(slides_data)}")
    return output_path


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--outline", required=True)
    parser.add_argument("--out-dir", required=True)
    args = parser.parse_args()

    generate_reveal(args.outline, args.out_dir)
