#!/usr/bin/env python3
"""
Gamma API Client — v2 (uses public-api.gamma.app/v1.0)
Converts slide outline YAML → markdown → POST to Gamma Generate API → polls → returns gammaUrl
"""

import json
import os
import sys
import time
import subprocess

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

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

BASE_URL = "https://public-api.gamma.app/v1.0"

# Headers that pass Cloudflare (matching a real browser/curl)
_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "Accept": "application/json",
    "Content-Type": "application/json",
}


# ── Config ────────────────────────────────────────────────────────────────────

def load_config() -> dict:
    config_path = os.path.expanduser("~/.baoyu-skills/baoyu-slides/config.json")
    if os.path.exists(config_path):
        with open(config_path) as f:
            return json.load(f)
    return {}


def get_api_key() -> str:
    config = load_config()
    key = config.get("gamma_api_key") or os.environ.get("GAMMA_API_KEY", "")
    if not key:
        raise ValueError(
            "No Gamma API key found.\n"
            "Set it in ~/.baoyu-skills/baoyu-slides/config.json under 'gamma_api_key'\n"
            "or set the GAMMA_API_KEY environment variable."
        )
    return key


# ── Outline → Gamma markdown ──────────────────────────────────────────────────

def outline_to_gamma_markdown(outline: dict) -> str:
    """Convert our YAML outline to Gamma textMode markdown format."""
    deck = outline.get("deck", {})
    slides_data = outline.get("slides", [])

    lines = []

    # Title slide
    title = deck.get("title", "Presentation")
    subtitle = deck.get("subtitle", "")
    author = deck.get("author", "Bo Wang")
    affiliation = deck.get("affiliation", "Xaira Therapeutics")
    date = deck.get("date", "")

    lines.append(f"# {title}")
    if subtitle:
        lines.append(f"### {subtitle}")
    lines.append(f"{author} · {affiliation}")
    if date:
        lines.append(date)
    lines.append("")
    lines.append("---")
    lines.append("")

    for slide in slides_data:
        if slide.get("slide", 1) == 1:
            continue  # Title already added

        stype = slide.get("type", "content")
        stitle = slide.get("title", "")
        bullets = slide.get("bullets", [])
        data_point = slide.get("data_point", "")
        visual = slide.get("visual", "")
        image_prompt = slide.get("image_prompt", "")

        if stype == "transition":
            lines.append(f"# {stitle}")

        elif stype == "quote":
            lines.append(f"## {stitle}")
            if bullets:
                lines.append(f"> {bullets[0]}")
            for b in bullets[1:]:
                lines.append(f"- {b}")

        elif stype == "data":
            lines.append(f"## {stitle}")
            if visual:
                lines.append(f"*{visual}*")
            if data_point:
                lines.append(f"\n**Key finding:** {data_point}")

        elif stype == "comparison":
            lines.append(f"## {stitle}")
            if len(bullets) >= 2:
                mid = len(bullets) // 2
                left = bullets[:mid]
                right = bullets[mid:]
                lines.append("| Before | After |")
                lines.append("|--------|-------|")
                for l, r in zip(left, right):
                    lines.append(f"| {l} | {r} |")

        elif stype == "image":
            lines.append(f"## {stitle}")
            if image_prompt:
                lines.append(f"*{image_prompt}*")

        else:
            # Standard content
            lines.append(f"## {stitle}")
            for b in bullets:
                lines.append(f"- {b}")
            if data_point:
                lines.append(f"\n**{data_point}**")

        lines.append("")
        lines.append("---")
        lines.append("")

    return "\n".join(lines)


# ── API calls ─────────────────────────────────────────────────────────────────

def _request(method: str, path: str, api_key: str, payload: dict = None) -> dict:
    url = f"{BASE_URL}{path}"
    headers = {**_HEADERS, "X-API-KEY": api_key}
    try:
        resp = _requests.request(
            method, url,
            headers=headers,
            json=payload,
            timeout=30,
        )
        resp.raise_for_status()
        return resp.json()
    except _requests.HTTPError as e:
        body = e.response.text[:400] if e.response is not None else ""
        raise RuntimeError(f"Gamma API HTTP {e.response.status_code}: {body}")


def generate_presentation(
    input_text: str,
    api_key: str,
    text_mode: str = "preserve",   # preserve=use verbatim, generate=AI rewrites, condense=AI condenses
    theme: str = None,
    generate_images: bool = True,
) -> dict:
    """
    POST /generations → poll until complete → return full response.
    Returns dict with at least: generationId, status, gammaUrl, credits
    """
    payload = {
        "inputText": input_text,
        "format": "presentation",
        "textMode": text_mode,
    }
    if theme:
        payload["theme"] = theme
    if not generate_images:
        payload["generateImages"] = False

    print("  → Submitting to Gamma API...")
    resp = _request("POST", "/generations", api_key, payload)
    gen_id = resp.get("generationId")
    if not gen_id:
        raise RuntimeError(f"No generationId in response: {resp}")

    print(f"  → Generation started: {gen_id}")
    print("  → Polling for completion", end="", flush=True)

    # Poll up to 3 minutes
    for attempt in range(36):
        time.sleep(5)
        print(".", end="", flush=True)
        status_resp = _request("GET", f"/generations/{gen_id}", api_key)
        status = status_resp.get("status", "")
        if status == "completed":
            print(" done!")
            return status_resp
        if status == "failed":
            raise RuntimeError(f"Generation failed: {status_resp}")

    raise RuntimeError("Gamma generation timed out after 3 minutes")


# ── Public entry point ────────────────────────────────────────────────────────

def create_presentation_gamma(
    outline_path: str,
    theme: str = None,
    api_key: str = None,
    text_mode: str = "preserve",   # preserve=use outline verbatim, generate=AI rewrites
) -> dict:
    """
    Create a Gamma presentation from an outline YAML.
    Returns dict with gammaUrl and metadata.
    """
    if api_key is None:
        api_key = get_api_key()

    with open(outline_path) as f:
        outline = yaml.safe_load(f)

    markdown_content = outline_to_gamma_markdown(outline)
    deck_info = outline.get("deck", {})

    print(f"\n🎨 Gamma: generating '{deck_info.get('title', 'Presentation')}'")
    print(f"   Slides: {len(outline.get('slides', []))}")
    print(f"   Mode: {text_mode}")

    result = generate_presentation(
        input_text=markdown_content,
        api_key=api_key,
        text_mode=text_mode,
        theme=theme,
    )

    gamma_url = result.get("gammaUrl", "")
    credits = result.get("credits", {})

    print(f"\n✅ Gamma presentation ready!")
    print(f"   URL: {gamma_url}")
    print(f"   Credits used: {credits.get('deducted', '?')} (remaining: {credits.get('remaining', '?')})")

    # Save markdown alongside outline for reference
    md_path = outline_path.replace(".yaml", "-gamma.md")
    with open(md_path, "w") as f:
        f.write(markdown_content)
    print(f"   Markdown saved: {md_path}")

    return {
        "url": gamma_url,
        "gammaId": result.get("gammaId"),
        "generationId": result.get("generationId"),
        "credits": credits,
        "markdown_path": md_path,
        "status": "completed",
    }


def gamma_markdown_to_file(outline_path: str, output_path: str = None) -> str:
    """Just convert outline to Gamma markdown, no API call."""
    try:
        with open(outline_path) as f:
            outline = yaml.safe_load(f)
    except Exception as e:
        print(f"Failed to parse outline YAML: {e}", file=sys.stderr)
        sys.exit(1)

    markdown = outline_to_gamma_markdown(outline)
    if output_path is None:
        output_path = outline_path.replace(".yaml", "-gamma.md")

    with open(output_path, "w") as f:
        f.write(markdown)
    print(f"✓ Gamma markdown saved: {output_path}")
    return output_path


# ── CLI ───────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="Gamma API slide generator")
    parser.add_argument("--outline", required=True, help="Path to slide-outline.yaml")
    parser.add_argument("--api-key", help="Gamma API key (overrides config)")
    parser.add_argument("--theme", default=None, help="Gamma theme name")
    parser.add_argument("--text-mode", default="preserve", choices=["preserve", "generate", "condense"],
                        help="text=use outline verbatim, generate=let Gamma AI rewrite")
    parser.add_argument("--markdown-only", action="store_true",
                        help="Just output Gamma markdown, no API call")
    args = parser.parse_args()

    if args.markdown_only:
        gamma_markdown_to_file(args.outline)
    else:
        result = create_presentation_gamma(
            outline_path=args.outline,
            theme=args.theme,
            api_key=args.api_key,
            text_mode=args.text_mode,
        )
        print(json.dumps(result, indent=2))
