import pytest

from autoshorts.content.brief import create_content_brief
from autoshorts.content.script_draft import create_script_draft
from autoshorts.rendering.manifest import (
    RenderManifest,
    RenderSettings,
    build_render_manifest,
    validate_render_manifest,
)
from autoshorts.rendering.shot_plan import ShotPlan, ShotScene, create_shot_plan


def _shot_plan():
    brief = create_content_brief(
        pillar_id="ai_life_systems",
        topic="AI weekly review routine",
        audience_problem="I use AI tools but still lose control of priorities.",
        payoff="a 10-minute Sunday review that keeps AI as assistant, not boss",
    )
    script = create_script_draft(brief)
    return create_shot_plan(script)


def test_build_render_manifest_turns_shot_plan_into_vertical_timeline():
    plan = _shot_plan()

    manifest = build_render_manifest(plan)

    assert isinstance(manifest, RenderManifest)
    assert manifest.script_id == "ai_life_systems-ai-weekly-review-routine"
    assert manifest.title == "AI weekly review routine"
    assert manifest.settings == RenderSettings(
        width=1080,
        height=1920,
        fps=30,
        no_generated_text_inside_assets=True,
        captions_renderer_owned=True,
        static_card_limit=0,
    )
    assert len(manifest.timeline) == len(plan.scenes)
    assert [item.scene_purpose for item in manifest.timeline] == [scene.purpose for scene in plan.scenes]
    assert manifest.timeline[0].start_seconds == 0
    assert manifest.timeline[-1].end_seconds == 35
    assert manifest.timeline[0].placeholder_asset_path == (
        "placeholders/ai_life_systems-ai-weekly-review-routine/01-first_frame_hook.png"
    )
    assert all(item.caption_layer.renderer_owned for item in manifest.timeline)
    assert all(item.label_layer.renderer_owned for item in manifest.timeline)
    assert all("static" not in item.motion_instruction.casefold() for item in manifest.timeline)


def test_validate_render_manifest_accepts_default_manifest():
    result = validate_render_manifest(build_render_manifest(_shot_plan()))

    assert result.is_valid is True
    assert result.errors == ()


def test_build_render_manifest_rejects_invalid_shot_plan():
    invalid_plan = ShotPlan(
        script_id="script",
        title="Title",
        estimated_duration_seconds=35,
        scenes=(
            ShotScene(
                purpose="first_frame_hook",
                start_seconds=0,
                end_seconds=3,
                voiceover_beat="Hook",
                visual_action="Static card",
                asset_mode="static_slideshow",
                caption_beat="Hook",
                retention_goal="Stop scroll",
            ),
        ),
    )

    with pytest.raises(ValueError, match="static slideshow asset mode is not allowed"):
        build_render_manifest(invalid_plan)


def test_validate_render_manifest_rejects_unsafe_render_settings():
    manifest = build_render_manifest(_shot_plan())
    unsafe = RenderManifest(
        script_id=manifest.script_id,
        title=manifest.title,
        settings=RenderSettings(
            width=1920,
            height=1080,
            fps=24,
            no_generated_text_inside_assets=False,
            captions_renderer_owned=False,
            static_card_limit=1,
        ),
        timeline=manifest.timeline,
    )

    result = validate_render_manifest(unsafe)

    assert result.is_valid is False
    assert "render size must be vertical 1080x1920" in result.errors
    assert "fps must be 30" in result.errors
    assert "generated text inside assets is not allowed" in result.errors
    assert "captions must be renderer-owned" in result.errors
    assert "static_card_limit must be 0" in result.errors


def test_validate_render_manifest_rejects_timeline_items_without_renderer_owned_layers():
    manifest = build_render_manifest(_shot_plan())
    first = manifest.timeline[0]
    bad_item = type(first)(
        scene_purpose=first.scene_purpose,
        start_seconds=first.start_seconds,
        end_seconds=first.end_seconds,
        asset_mode=first.asset_mode,
        motion_instruction=first.motion_instruction,
        placeholder_asset_path=first.placeholder_asset_path,
        caption_layer=type(first.caption_layer)(text=first.caption_layer.text, renderer_owned=False),
        label_layer=type(first.label_layer)(text=first.label_layer.text, renderer_owned=False),
    )
    unsafe = RenderManifest(
        script_id=manifest.script_id,
        title=manifest.title,
        settings=manifest.settings,
        timeline=(bad_item,) + manifest.timeline[1:],
    )

    result = validate_render_manifest(unsafe)

    assert result.is_valid is False
    assert "timeline item 1 caption layer must be renderer-owned" in result.errors
    assert "timeline item 1 label layer must be renderer-owned" in result.errors
