from pathlib import Path
import subprocess

from autoshorts.audio.voiceover import build_truetrace_final_voiceover
from autoshorts.rendering.final_video_plan import build_truetrace_weird_email_final_video_plan
from autoshorts.rendering.motion_renderer import (
    MotionRenderResult,
    build_motion_render_plan,
    render_motion_preview,
    validate_motion_render_plan,
)


def test_build_motion_render_plan_maps_final_plan_to_frame_output(tmp_path):
    voiceover = build_truetrace_final_voiceover("truetrace-ai-automation-quiet-rot-38s")
    final_plan = build_truetrace_weird_email_final_video_plan(voiceover)

    background_paths = {scene.scene_id: tmp_path / f"{scene.scene_id}.png" for scene in final_plan.scenes}
    for path in background_paths.values():
        path.write_bytes(b"fake image")
    render_plan = build_motion_render_plan(
        final_plan,
        output_dir=tmp_path,
        preview_scale=0.5,
        background_paths=background_paths,
    )

    assert render_plan.background_paths == {scene_id: str(path) for scene_id, path in background_paths.items()}
    assert render_plan.width == 540
    assert render_plan.height == 960
    assert render_plan.fps == 24
    assert render_plan.output_path.endswith("motion-preview.mp4")
    assert render_plan.frame_dir.endswith("frames")
    assert render_plan.concat_path.endswith("frames.txt")
    assert render_plan.side_effects == ()
    assert render_plan.external_calls == ()
    validation = validate_motion_render_plan(render_plan)
    assert validation.is_valid is True


def test_render_motion_preview_writes_frames_and_invokes_ffmpeg(tmp_path):
    voiceover = build_truetrace_final_voiceover("truetrace-ai-automation-quiet-rot-38s")
    final_plan = build_truetrace_weird_email_final_video_plan(voiceover)
    render_plan = build_motion_render_plan(final_plan, output_dir=tmp_path, preview_scale=0.5)
    calls = []

    def fake_runner(command, *, capture_output, text, check):
        calls.append(command)
        Path(render_plan.output_path).write_bytes(b"fake mp4")
        return subprocess.CompletedProcess(command, 0, stdout="ok", stderr="")

    result = render_motion_preview(render_plan, runner=fake_runner, max_frames_per_scene=2)

    assert isinstance(result, MotionRenderResult)
    assert len(result.frame_paths) == 10
    assert all(Path(path).exists() for path in result.frame_paths)
    assert Path(render_plan.concat_path).exists()
    assert calls
    assert calls[0][0] == "ffmpeg"
    assert "-f" in calls[0]
    assert result.side_effects == ("write_png", "write_concat", "call_ffmpeg", "write_mp4")
    assert result.external_calls == ("ffmpeg",)
