#!/usr/bin/env python3
"""
Insert Spoken Institute storyboard frames into Google Slides deck.
Uses gws-auth CLI to upload images and update slides.
"""

import json
import subprocess
import sys
import os

WORKING_DIR = "/root/.openclaw/workspace/work/internal-ce/operations/products/spoken-institute"
PRESENTATION_ID = "1dMNGiMgjX7acC8f1o6vl1L7qiQSwP9GymNKBR-J0xFM"
TOKEN_PATH = "/root/.openclaw/workspace/google-auth/token.json"

# Frame definitions: (filename, slide_id, existing_image_id, copy_text)
FRAMES = [
    {
        "id": 1,
        "filename": "frame1-list-v3-2026-03-13-21-15-11.png",
        "slide_id": "scene_f1",
        "old_image_id": "g3cff2428bdb_0_75",
        "copy": "Do you have something to say about eight of these?",
        "time_label": "",
    },
    {
        "id": 2,
        "filename": "frame2-physicist-v1-2026-03-14.png",
        "slide_id": "scene_f2",
        "old_image_id": "g3cff2428bdb_2_25",
        "copy": "You know why it works. That's rare.",
        "time_label": "7:30 AM",
    },
    {
        "id": 3,
        "filename": "frame3-mentor-v1-2026-03-14.png",
        "slide_id": "scene_f3",
        "old_image_id": "g3cff2428bdb_2_27",
        "copy": "Physics isn't your subject. It's your language.",
        "time_label": "12:00 PM",
    },
    {
        "id": 4,
        "filename": "frame4-connector-v1-2026-03-14.png",
        "slide_id": "scene_f4",
        "old_image_id": "g3cff2428bdb_2_26",
        "copy": "You're already making the next one.",
        "time_label": "4:00 PM",
    },
    {
        "id": 5,
        "filename": "frame5-student-v1-2026-03-14.png",
        "slide_id": "g3cff2428bdb_2_46",
        "old_image_id": "g3cff2428bdb_2_54",
        "copy": "You can't turn it off. Good.",
        "time_label": "9:00 PM",
    },
]

# Slide dimensions in EMU (16:9, standard)
SLIDE_WIDTH = 9144000
SLIDE_HEIGHT = 5143500


def run_gws(args, input_data=None):
    """Run gws-auth command and return JSON output."""
    cmd = ["gws-auth"] + args
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        input=input_data,
        cwd=WORKING_DIR,
    )
    if result.returncode != 0:
        print(f"  ERROR: {result.stderr[:200]}")
        return None
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        print(f"  ERROR parsing JSON: {result.stdout[:200]}")
        return None


def upload_to_drive(filepath, name):
    """Upload file to Drive and return file ID."""
    print(f"  Uploading {name}...")
    result = run_gws([
        "drive", "files", "create",
        "--params", json.dumps({
            "fields": "id,webViewLink,webContentLink"
        }),
        "--upload", filepath,
        "--json", json.dumps({
            "name": name,
            "parents": []
        })
    ])
    if result and "id" in result:
        file_id = result["id"]
        print(f"  Uploaded: {file_id}")
        return file_id
    print(f"  Upload failed: {result}")
    return None


def make_public(file_id):
    """Make Drive file publicly readable and return web content URL."""
    print(f"  Making public: {file_id}")
    result = run_gws([
        "drive", "permissions", "create",
        "--params", json.dumps({"fileId": file_id, "fields": "id"}),
        "--json", json.dumps({"role": "reader", "type": "anyone"})
    ])
    if not result:
        print(f"  Permission grant failed for {file_id}")
        return None
    # Return the direct download URL
    url = f"https://drive.google.com/uc?export=view&id={file_id}"
    print(f"  Public URL: {url}")
    return url


def build_batch_update(frame, image_url):
    """Build batchUpdate requests to replace image and update copy on a slide."""
    requests = []

    # 1. Delete existing image
    requests.append({
        "deleteObject": {
            "objectId": frame["old_image_id"]
        }
    })

    # 2. Create new full-bleed image
    new_image_id = f"frame{frame['id']}_img_new"
    requests.append({
        "createImage": {
            "objectId": new_image_id,
            "url": image_url,
            "elementProperties": {
                "pageObjectId": frame["slide_id"],
                "size": {
                    "width": {"magnitude": SLIDE_WIDTH, "unit": "EMU"},
                    "height": {"magnitude": SLIDE_HEIGHT, "unit": "EMU"}
                },
                "transform": {
                    "scaleX": 1, "scaleY": 1,
                    "translateX": 0, "translateY": 0,
                    "unit": "EMU"
                }
            }
        }
    })

    # 3. Send image to back (behind text elements)
    requests.append({
        "updatePageElementsZOrder": {
            "pageElementObjectIds": [new_image_id],
            "operation": "SEND_TO_BACK"
        }
    })

    return requests


def update_text_in_slide(slide_id, slide_info, frame):
    """Build requests to update text elements with locked copy."""
    requests = []
    
    # Map of text element IDs to their new content
    # Based on our slide inspection, update the title/premise text boxes
    text_updates = {}
    
    if frame["id"] == 1:
        text_updates = {
            "shot_f1": "Scene 1: The List",
            "prem_f1": "The teacher's mind — revealed",
            "titl_f1": frame["copy"],
        }
    elif frame["id"] == 2:
        text_updates = {
            "shot_f2": f"Scene 2: The Physicist · {frame['time_label']}",
            "prem_f2": "Teaching physics like a language",
            "titl_f2": frame["copy"],
        }
    elif frame["id"] == 3:
        text_updates = {
            "shot_f3": f"Scene 3: The Mentor · {frame['time_label']}",
            "prem_f3": "Building the next teacher",
            "titl_f3": frame["copy"],
        }
    elif frame["id"] == 4:
        text_updates = {
            "shot_f4": f"Scene 4: The Connector · {frame['time_label']}",
            "prem_f4": "Connecting science, philosophy, technology",
            "titl_f4": frame["copy"],
        }
    elif frame["id"] == 5:
        # Slide 10 uses different IDs
        text_updates = {
            "g3cff2428bdb_2_47": f"Scene 5: The Student · {frame['time_label']}",
            "g3cff2428bdb_2_48": "Still learning",
            "g3cff2428bdb_2_49": frame["copy"],
        }

    for obj_id, new_text in text_updates.items():
        # Clear existing text
        requests.append({
            "deleteText": {
                "objectId": obj_id,
                "textRange": {"type": "ALL"}
            }
        })
        # Insert new text
        requests.append({
            "insertText": {
                "objectId": obj_id,
                "insertionIndex": 0,
                "text": new_text
            }
        })

    return requests


def apply_batch_update(all_requests):
    """Apply all batchUpdate requests to the presentation."""
    body = {"requests": all_requests}
    result = run_gws([
        "slides", "presentations", "batchUpdate",
        "--params", json.dumps({"presentationId": PRESENTATION_ID}),
        "--json", json.dumps(body)
    ])
    return result


def main():
    print("=== Spoken Institute Storyboard → Google Slides ===\n")
    
    all_requests = []
    uploaded_frames = []

    for frame in FRAMES:
        filepath = os.path.join(WORKING_DIR, frame["filename"])
        print(f"\nFrame {frame['id']}: {frame['filename']}")
        
        if not os.path.exists(filepath):
            print(f"  WARNING: File not found: {filepath}")
            continue

        # Upload to Drive
        file_id = upload_to_drive(filepath, frame["filename"])
        if not file_id:
            print(f"  SKIP: Upload failed")
            continue

        # Make public
        image_url = make_public(file_id)
        if not image_url:
            print(f"  SKIP: Could not make public")
            continue

        # Build batch requests
        img_requests = build_batch_update(frame, image_url)
        all_requests.extend(img_requests)

        # Add text update requests
        # txt_requests = update_text_in_slide(frame["slide_id"], {}, frame)
        # all_requests.extend(txt_requests)

        uploaded_frames.append({
            "frame_id": frame["id"],
            "file_id": file_id,
            "url": image_url,
            "slide_id": frame["slide_id"]
        })
        print(f"  Ready: frame{frame['id']} → slide [{frame['slide_id']}]")

    if not all_requests:
        print("\nNo requests to apply.")
        return

    print(f"\nApplying {len(all_requests)} requests to deck...")
    result = apply_batch_update(all_requests)
    
    if result:
        print("\n✅ Done!")
        print(f"Deck: https://docs.google.com/presentation/d/{PRESENTATION_ID}/edit")
        print(f"\nFrames inserted:")
        for f in uploaded_frames:
            print(f"  Frame {f['frame_id']} → slide {f['slide_id']}")
    else:
        print("\n❌ Batch update failed. Check errors above.")
        print("\nUploaded frames (can retry):")
        for f in uploaded_frames:
            print(f"  Frame {f['frame_id']}: Drive file {f['file_id']}, URL: {f['url']}")


if __name__ == "__main__":
    main()
