#!/usr/bin/env python3
"""
Google Slides Generator
Creates a formatted Google Slides deck from slide outline YAML.
Uses gws slides API (already authenticated).
"""

import argparse
import json
import os
import subprocess
import sys

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

# Bo's presentation color scheme
COLORS = {
    "bg_dark": {"red": 0.102, "green": 0.102, "blue": 0.180},      # #1a1a2e deep navy
    "bg_slide": {"red": 0.98, "green": 0.98, "blue": 0.99},         # near white
    "accent": {"red": 0.231, "green": 0.510, "blue": 0.965},        # #3b82f6 blue
    "accent2": {"red": 0.059, "green": 0.780, "blue": 0.647},       # #0fc8a5 teal
    "text_dark": {"red": 0.13, "green": 0.13, "blue": 0.18},
    "text_light": {"red": 1.0, "green": 1.0, "blue": 1.0},
    "text_muted": {"red": 0.45, "green": 0.45, "blue": 0.55},
}

PT_UNIT = 12700  # EMU per point


def gws(resource: str, method: str, params: dict = None, body: dict = None) -> dict:
    """Call gws CLI and return parsed JSON."""
    cmd = ["gws"] + resource.split() + [method]
    if params:
        cmd += ["--params", json.dumps(params)]
    if body:
        cmd += ["--json", json.dumps(body)]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        raise RuntimeError(f"gws error: {result.stderr[:300]}")
    try:
        return json.loads(result.stdout)
    except:
        return {"raw": result.stdout}


def create_presentation(title: str) -> str:
    """Create a new Google Slides presentation and return its ID."""
    result = gws("slides presentations", "create",
                 body={"title": title})
    presentation_id = result.get("presentationId")
    print(f"✓ Created presentation: {title}")
    print(f"  ID: {presentation_id}")
    return presentation_id


def build_title_slide_requests(slide_id: str, deck: dict) -> list:
    """Build requests to populate the title slide."""
    requests = []
    title = deck.get('title', 'Presentation')
    subtitle = f"{deck.get('author', 'Bo Wang')} | {deck.get('affiliation', 'Xaira Therapeutics')}"
    if deck.get('date'):
        subtitle += f"\n{deck['date']}"

    # Get the existing placeholder IDs
    requests.append({
        "deleteObject": {"objectId": slide_id}  # We'll use a different approach
    })
    return requests


def add_slide_requests(presentation_id: str, slides_data: list, deck: dict) -> list:
    """Build all batch update requests for slide content."""
    requests = []
    slide_ids = []

    for i, slide in enumerate(slides_data):
        slide_id = f"slide_{i+1:02d}"
        slide_ids.append(slide_id)
        slide_type = slide.get('type', 'content')

        # Create slide
        layout_map = {
            'title': 'TITLE',
            'content': 'TITLE_AND_BODY',
            'data': 'TITLE_AND_BODY',
            'comparison': 'TITLE_AND_TWO_COLUMNS',
            'quote': 'TITLE_AND_BODY',
            'transition': 'SECTION_HEADER',
            'image': 'TITLE_AND_BODY',
        }
        layout = layout_map.get(slide_type, 'TITLE_AND_BODY')

        requests.append({
            "createSlide": {
                "objectId": slide_id,
                "slideLayoutReference": {"predefinedLayout": layout},
            }
        })

    return requests, slide_ids


def populate_slides_requests(presentation_id: str, slide_info: list, slides_data: list) -> list:
    """After slides are created, populate them with content."""
    requests = []

    for slide, slide_dict in zip(slide_info, slides_data):
        slide_id = slide['slideObjectId']
        elements = {e.get('shape', {}).get('placeholder', {}).get('type', ''):
                    e['objectId'] for e in slide.get('pageElements', [])
                    if 'shape' in e and 'placeholder' in e.get('shape', {})}

        title_id = elements.get('TITLE') or elements.get('CENTERED_TITLE')
        body_id = elements.get('BODY') or elements.get('SUBTITLE')

        slide_data = slide_dict
        title_text = slide_data.get('title', '')
        bullets = slide_data.get('bullets', [])
        data_point = slide_data.get('data_point', '')
        speaker_notes = slide_data.get('speaker_notes', '')
        slide_type = slide_data.get('type', 'content')

        if title_id and title_text:
            requests.append({
                "insertText": {
                    "objectId": title_id,
                    "text": title_text,
                    "insertionIndex": 0,
                }
            })
            # Style title
            requests.append({
                "updateTextStyle": {
                    "objectId": title_id,
                    "textRange": {"type": "ALL"},
                    "style": {
                        "fontSize": {"magnitude": 28 if slide_type == 'title' else 22, "unit": "PT"},
                        "foregroundColor": {"opaqueColor": {"rgbColor": COLORS["text_dark"]}},
                        "bold": True,
                        "fontFamily": "Google Sans",
                    },
                    "fields": "fontSize,foregroundColor,bold,fontFamily",
                }
            })

        if body_id:
            body_lines = []
            if slide_type == 'title':
                deck_subtitle = slide_data.get('subtitle', '')
                if deck_subtitle:
                    body_lines.append(deck_subtitle)
            else:
                body_lines.extend(bullets)
                if data_point:
                    body_lines.append('')
                    body_lines.append(f"► {data_point}")

            if body_lines:
                body_text = '\n'.join(body_lines)
                requests.append({
                    "insertText": {
                        "objectId": body_id,
                        "text": body_text,
                        "insertionIndex": 0,
                    }
                })

        # Speaker notes
        notes_id = slide.get('slideProperties', {}).get('notesPage', {}).get(
            'notesProperties', {}).get('speakerNotesObjectId')
        if not notes_id:
            # Find speaker notes from page elements
            for elem in slide.get('pageElements', []):
                if elem.get('shape', {}).get('placeholder', {}).get('type') == 'BODY':
                    # This might be the notes area — handled differently
                    pass

        if speaker_notes and notes_id:
            requests.append({
                "insertText": {
                    "objectId": notes_id,
                    "text": speaker_notes.strip(),
                    "insertionIndex": 0,
                }
            })

    return requests


def create_from_outline(outline_path: str, title: str = None) -> str:
    """Main function: create Google Slides deck from outline YAML."""
    with open(outline_path) as f:
        outline = yaml.safe_load(f)

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

    if not title:
        title = deck.get('title', 'Presentation')

    # Step 1: Create presentation
    presentation_id = create_presentation(title)

    # Step 2: Delete default blank slide, add our slides
    print(f"📊 Building {len(slides_data)} slides...")

    # Get current state
    current = gws("slides presentations", "get",
                  params={"presentationId": presentation_id})
    default_slide_id = current['slides'][0]['objectId']

    # Build slide creation requests
    slide_requests = []
    slide_ids = []
    for i, slide in enumerate(slides_data):
        sid = f"s{i+1:02d}_{slide.get('type', 'content')}"
        slide_ids.append(sid)
        layout_map = {
            'title': 'TITLE',
            'transition': 'SECTION_HEADER',
            'comparison': 'TITLE_AND_TWO_COLUMNS',
        }
        layout = layout_map.get(slide.get('type', 'content'), 'TITLE_AND_BODY')
        slide_requests.append({
            "createSlide": {
                "objectId": sid,
                "insertionIndex": i,
                "slideLayoutReference": {"predefinedLayout": layout},
            }
        })

    # Delete original blank slide
    slide_requests.append({"deleteObject": {"objectId": default_slide_id}})

    gws("slides presentations", "batchUpdate",
        params={"presentationId": presentation_id},
        body={"requests": slide_requests})

    # Step 3: Get updated presentation to find element IDs
    current = gws("slides presentations", "get",
                  params={"presentationId": presentation_id})

    # Step 4: Populate content
    print("✍️  Populating content and speaker notes...")
    content_requests = []

    for slide_page, slide_data in zip(current.get('slides', []), slides_data):
        elements = {}
        for elem in slide_page.get('pageElements', []):
            ph_type = elem.get('shape', {}).get('placeholder', {}).get('type', '')
            if ph_type:
                elements[ph_type] = elem['objectId']

        title_id = elements.get('CENTERED_TITLE') or elements.get('TITLE')
        body_id = elements.get('SUBTITLE') or elements.get('BODY')
        notes_id = slide_page.get('slideProperties', {}).get(
            'notesPage', {}).get('pageElements', [{}])

        title_text = slide_data.get('title', '')
        bullets = slide_data.get('bullets', [])
        data_point = slide_data.get('data_point', '')
        speaker_notes = str(slide_data.get('speaker_notes', '')).strip()
        slide_type = slide_data.get('type', 'content')

        # Title
        if title_id and title_text:
            content_requests.append({
                "insertText": {"objectId": title_id, "text": title_text, "insertionIndex": 0}
            })

        # Body content
        if body_id:
            if slide_type == 'title':
                body_text = slide_data.get('subtitle', '') or f"{deck.get('author','')} | {deck.get('affiliation','')}"
            else:
                parts = list(bullets)
                if data_point:
                    parts.extend(['', f'► {data_point}'])
                body_text = '\n'.join(parts)

            if body_text.strip():
                content_requests.append({
                    "insertText": {"objectId": body_id, "text": body_text, "insertionIndex": 0}
                })

        # Speaker notes — find notes placeholder
        for elem in slide_page.get('pageElements', []):
            if elem.get('shape', {}).get('shapeType') == 'TEXT_BOX':
                pass
        notes_page = slide_page.get('slideProperties', {}).get('notesPage', {})
        for elem in notes_page.get('pageElements', []):
            ph = elem.get('shape', {}).get('placeholder', {})
            if ph.get('type') == 'BODY' and speaker_notes:
                content_requests.append({
                    "insertText": {
                        "objectId": elem['objectId'],
                        "text": speaker_notes,
                        "insertionIndex": 0
                    }
                })

    if content_requests:
        # Split into batches of 50 (API limit)
        for i in range(0, len(content_requests), 50):
            batch = content_requests[i:i+50]
            gws("slides presentations", "batchUpdate",
                params={"presentationId": presentation_id},
                body={"requests": batch})

    url = f"https://docs.google.com/presentation/d/{presentation_id}/edit"
    print(f"\n✅ Google Slides deck created!")
    print(f"   URL: {url}")
    print(f"   Slides: {len(slides_data)}")
    return url


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--outline", required=True)
    parser.add_argument("--title", help="Override deck title")
    args = parser.parse_args()

    url = create_from_outline(args.outline, args.title)
    print(url)
