"""Asset planning for final, motion-led AutoShortsBot renders.

This layer converts render manifests into explicit asset-generation plans so final
videos can use local procedural motion, screen-recording simulations, kinetic
overlays, and mechanism animations instead of static text slides. The plan is
budget-safe: paid video-credit providers are not required.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from autoshorts.script_drafts import _slug

SCENE_MODE_BY_TYPE = {
    "kinetic_text": "kinetic_text_overlay",
    "screen_recording": "screen_recording_simulation",
    "card_animation": "animated_card",
    "stock_broll": "cinematic_ai_video",
    "generated_background": "cinematic_ai_video",
    "cinematic_ai_video": "cinematic_ai_video",
    "mechanism_animation": "mechanism_animation",
    "kinetic_text_overlay": "kinetic_text_overlay",
}


# Scene-level overrides keep AI/productivity videos from becoming five text cards.
SCENE_MODE_OVERRIDES = {
    "ai_life_systems": {
        "scene_01": "cinematic_ai_video",
        "scene_02": "screen_recording_simulation",
        "scene_03": "animated_card",
        "scene_04": "screen_recording_simulation",
        "scene_05": "kinetic_text_overlay",
    },
    "attention_design": {
        "scene_01": "cinematic_ai_video",
        "scene_02": "cinematic_ai_video",
        "scene_03": "animated_card",
        "scene_04": "screen_recording_simulation",
        "scene_05": "kinetic_text_overlay",
    },
}


def _visual_items(manifest: dict[str, Any]) -> list[dict[str, Any]]:
    return [item for item in manifest["timeline"] if item["track"] == "visual"]


def _duration_seconds(item: dict[str, Any]) -> int | float:
    seconds = int(item["duration_ms"]) / 1000
    if item.get("type") in {"cinematic_ai_video", "mechanism_animation", "kinetic_text_overlay"}:
        return int(seconds) if seconds.is_integer() else seconds
    return max(3, min(6, round(seconds)))


def _asset_mode(item: dict[str, Any], pillar: str) -> str:
    override = SCENE_MODE_OVERRIDES.get(pillar, {}).get(item["id"])
    if override:
        return override
    return SCENE_MODE_BY_TYPE.get(item["type"], "cinematic_ai_video")


def _camera_motion(scene_id: str, mode: str) -> str:
    if mode == "cinematic_ai_video":
        return "slow handheld push-in, subtle parallax, natural micro-movements"
    if mode == "screen_recording_simulation":
        return "cursor movement, typing reveal, zoom to changed prompt, highlighted selection box"
    if mode == "animated_card":
        return "cards slide in one at a time, one concept per beat, slight scale pops"
    return "large kinetic caption words pop and slide with beat-synced emphasis"


def _cinematic_subject(pillar: str, text: str) -> str:
    if pillar == "attention_design":
        return (
            "a realistic person holding a phone in a dim modern room, thumb hovering over an endless feed, "
            "then a decisive pause as the screen glow reflects on their face"
        )
    return (
        "a realistic creator at a desk late evening, laptop open to an AI chat, thoughtful but in control, "
        "hands moving between keyboard and notebook"
    )


def _generation_prompt(item: dict[str, Any], manifest: dict[str, Any], mode: str) -> str:
    video = manifest["video"]
    text = item["text"]
    if mode == "cinematic_ai_video":
        subject = _cinematic_subject(video["pillar"], text)
        return (
            f"Vertical 9:16 cinematic-looking local motion scene, {subject}. "
            f"Mood: focused, modern, high-retention social video, dramatic lighting simulated with gradients and shadows. "
            f"Scene intent: {item['visual_direction']} Camera: {_camera_motion(item['id'], mode)}. "
            "Use local procedural animation/parallax rather than paid AI-video credits; keep captions renderer-overlay only."
        )
    if mode == "screen_recording_simulation":
        return (
            "Vertical 9:16 UI/screen-recording simulation. Show an AI chat or phone interface being edited live: "
            f"{item['visual_direction']} Use typing, cursor movement, zoom highlights, and before/after prompt changes. "
            "All readable captions must be added by our renderer overlay, not baked into the clip."
        )
    if mode == "animated_card":
        return (
            "Vertical animated explainer card sequence. Minimal dark UI, one idea per beat, animated boxes and arrows. "
            f"Visual task: {item['visual_direction']} Keep it moving; no static slide holds longer than one second."
        )
    if mode == "mechanism_animation":
        return (
            "Vertical 9:16 mechanism-reveal animation. Build a clear visual explanation with moving layers, x-ray/röntgen reveal, "
            "arrows, meters, object cutaways, and sequential labels added by our renderer. "
            f"Mechanism task: {item['visual_direction']} Motion: {item.get('visual_motion', _camera_motion(item['id'], mode))}. "
            "No static holds longer than one second; keep all readable text as renderer overlays."
        )
    return (
        "Kinetic text overlay scene. Use large caption words, fast emphasis, scale pops, and clean background motion. "
        f"Overlay text: {text}"
    )


def _negative_prompt(mode: str) -> str:
    if mode == "cinematic_ai_video":
        return (
            "no readable text, no subtitles, no logos, no watermarks, no distorted hands, no fake UI text, "
            "no slideshow, no static image, no uncanny faces"
        )
    if mode == "screen_recording_simulation":
        return "no private data, no real credentials, no illegible tiny UI, no brand logos unless approved"
    if mode == "animated_card":
        return "no dense paragraphs, no static PowerPoint slide, no tiny text, no chart junk"
    if mode == "mechanism_animation":
        return "no static diagram, no dense labels, no tiny text, no unreadable chart junk, no generic infographic"
    return "no long paragraphs, no tiny footnotes, no static card"


def _scene_asset_plan(item: dict[str, Any], manifest: dict[str, Any]) -> dict[str, Any]:
    video = manifest["video"]
    mode = _asset_mode(item, video["pillar"])
    return {
        "scene_id": item["id"],
        "asset_ref": item["asset_ref"],
        "asset_mode": mode,
        "provider_family": "local_free_renderer",
        "duration_seconds": _duration_seconds(item),
        "overlay_text": item["text"],
        "caption_strategy": "renderer_overlay_only",
        "no_text_in_video": mode == "cinematic_ai_video",
        "motion_directive": _camera_motion(item["id"], mode),
        "generation_prompt": _generation_prompt(item, manifest, mode),
        "negative_prompt": _negative_prompt(mode),
        "retention_goal": item["retention_goal"],
        "source_visual_direction": item["visual_direction"],
    }


def build_asset_plan(manifest: dict[str, Any]) -> dict[str, Any]:
    """Build a final-render asset plan from a render manifest."""
    scenes = [_scene_asset_plan(item, manifest) for item in _visual_items(manifest)]
    modes = [scene["asset_mode"] for scene in scenes]
    return {
        "schema_version": "asset_plan.v2",
        "video": manifest["video"],
        "scenes": scenes,
        "final_render_strategy": {
            "preview_renderer_role": "storyboard_only",
            "budget_policy": "free_only_no_paid_video_credits",
            "static_card_limit": 0,
            "must_use_motion_assets": True,
            "preferred_mix": {
                "cinematic_ai_video": modes.count("cinematic_ai_video"),
                "screen_recording_simulation": modes.count("screen_recording_simulation"),
                "animated_card": modes.count("animated_card"),
                "mechanism_animation": modes.count("mechanism_animation"),
                "kinetic_text_overlay": modes.count("kinetic_text_overlay"),
            },
            "captions": "large kinetic overlays generated by renderer; no baked text in AI clips",
            "approval_required_before_publish": True,
        },
    }


def _asset_plan_filename(video: dict[str, Any]) -> str:
    title_slug = _slug(video["title"])
    video_id = video["id"]
    if video_id.endswith(title_slug):
        return f"{video_id}.json"
    return f"{video_id}-{title_slug}.json"


def write_asset_plans(manifests: list[dict[str, Any]], output_dir: Path) -> list[Path]:
    """Write asset plans as JSON files."""
    output_dir.mkdir(parents=True, exist_ok=True)
    paths: list[Path] = []
    for manifest in manifests:
        plan = build_asset_plan(manifest)
        path = output_dir / _asset_plan_filename(plan["video"])
        path.write_text(json.dumps(plan, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
        paths.append(path)
    return paths
