"""Tests for render_video module."""

from __future__ import annotations

from typing import TYPE_CHECKING
from unittest.mock import Mock, patch

import pytest

from mcp_vm_blackbox.demo_manifest import ReplayBundle
from mcp_vm_blackbox.render_video import render_video

if TYPE_CHECKING:
    from pathlib import Path


class TestRenderVideo:
    """Tests for render_video function."""

    def test_render_video_success(self, tmp_path: Path) -> None:
        """Test successful video rendering."""
        manifest_path = tmp_path / "manifest.json"
        manifest_path.write_text("{}", encoding="utf-8")
        output_dir = tmp_path / "output"
        output_dir.mkdir()

        # Create the expected output file in the mock
        expected_output = output_dir / "proof_video.mp4"

        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stderr = ""

        with patch("mcp_vm_blackbox.render_video.subprocess.run") as mock_run:
            # Make the mock actually create the file to simulate real behavior
            def side_effect_create_file(*args, **kwargs):
                expected_output.write_bytes(b"fake video content")
                return mock_result

            mock_run.side_effect = side_effect_create_file

            result = render_video(manifest_path, output_dir)

        assert result == expected_output.resolve()
        assert result.exists()
        assert result.stat().st_size > 0

        # Verify command structure
        call_args = mock_run.call_args
        cmd = call_args[0][0]
        assert "npx" in cmd
        assert "tsx" in cmd
        assert "--manifest" in cmd
        assert str(manifest_path) in cmd
        assert "--output" in cmd
        assert str(expected_output) in cmd

    def test_render_video_failure_nonzero_exit(self, tmp_path: Path) -> None:
        """Test that non-zero exit code raises RuntimeError with exit code and stderr."""
        manifest_path = tmp_path / "manifest.json"
        manifest_path.write_text("{}", encoding="utf-8")
        output_dir = tmp_path / "output"
        output_dir.mkdir()

        mock_result = Mock()
        mock_result.returncode = 1
        mock_result.stderr = "Error: Something went wrong"

        with patch("mcp_vm_blackbox.render_video.subprocess.run") as mock_run:
            mock_run.return_value = mock_result

            with pytest.raises(RuntimeError) as exc_info:
                render_video(manifest_path, output_dir)

        # Verify error message contains exit code and stderr (diagnostic check)
        error_msg = str(exc_info.value)
        assert "exit 1" in error_msg
        assert "Something went wrong" in error_msg

    def test_render_video_failure_missing_output(self, tmp_path: Path) -> None:
        """Test that missing output file raises RuntimeError with path detail."""
        manifest_path = tmp_path / "manifest.json"
        manifest_path.write_text("{}", encoding="utf-8")
        output_dir = tmp_path / "output"
        output_dir.mkdir()

        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stderr = ""

        with patch("mcp_vm_blackbox.render_video.subprocess.run") as mock_run:
            mock_run.return_value = mock_result

            with pytest.raises(RuntimeError) as exc_info:
                render_video(manifest_path, output_dir)

        # Verify error message contains expected output path
        error_msg = str(exc_info.value)
        expected_path = str(output_dir / "proof_video.mp4")
        assert expected_path in error_msg
        assert "no output" in error_msg.lower()

    def test_render_video_failure_empty_output(self, tmp_path: Path) -> None:
        """Test that empty output file raises RuntimeError."""
        manifest_path = tmp_path / "manifest.json"
        manifest_path.write_text("{}", encoding="utf-8")
        output_dir = tmp_path / "output"
        output_dir.mkdir()

        # Create 0-byte file
        expected_output = output_dir / "proof_video.mp4"
        expected_output.write_bytes(b"")

        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stderr = ""

        with patch("mcp_vm_blackbox.render_video.subprocess.run") as mock_run:
            mock_run.return_value = mock_result

            with pytest.raises(RuntimeError) as exc_info:
                render_video(manifest_path, output_dir)

        error_msg = str(exc_info.value)
        assert "empty output" in error_msg.lower()
        assert str(expected_output) in error_msg

    def test_render_video_with_repo_root(self, tmp_path: Path) -> None:
        """Test that repo_root is passed to CLI when provided."""
        manifest_path = tmp_path / "manifest.json"
        manifest_path.write_text("{}", encoding="utf-8")
        output_dir = tmp_path / "output"
        output_dir.mkdir()
        repo_root = tmp_path / "repo"

        expected_output = output_dir / "proof_video.mp4"

        mock_result = Mock()
        mock_result.returncode = 0
        mock_result.stderr = ""

        with patch("mcp_vm_blackbox.render_video.subprocess.run") as mock_run:

            def side_effect_create_file(*args, **kwargs):
                expected_output.write_bytes(b"fake video content")
                return mock_result

            mock_run.side_effect = side_effect_create_file

            render_video(manifest_path, output_dir, repo_root=repo_root)

        call_args = mock_run.call_args
        cmd = call_args[0][0]
        assert "--repo-root" in cmd
        assert str(repo_root) in cmd


class TestReplayBundleVideoOutputPath:
    """Tests for video_output_path field on ReplayBundle."""

    def test_video_output_path_roundtrip(self) -> None:
        """Test that video_output_path can be set and retrieved."""
        bundle = ReplayBundle(
            bundle_id="test-123",
            created_at="2025-01-01T00:00:00Z",
            description="Test bundle",
            primary_job_id="job-123",
            primary_vm_name="test-vm",
            primary_job_path="jobs/test.json",
            video_output_path="/tmp/x.mp4",
        )

        assert bundle.video_output_path == "/tmp/x.mp4"

    def test_video_output_path_default_none(self) -> None:
        """Test that video_output_path defaults to None."""
        bundle = ReplayBundle(
            bundle_id="test-123",
            created_at="2025-01-01T00:00:00Z",
            description="Test bundle",
            primary_job_id="job-123",
            primary_vm_name="test-vm",
            primary_job_path="jobs/test.json",
        )

        assert bundle.video_output_path is None

    def test_video_output_path_can_be_set_none(self) -> None:
        """Test that video_output_path can be explicitly set to None."""
        bundle = ReplayBundle(
            bundle_id="test-123",
            created_at="2025-01-01T00:00:00Z",
            description="Test bundle",
            primary_job_id="job-123",
            primary_vm_name="test-vm",
            primary_job_path="jobs/test.json",
            video_output_path=None,
        )

        assert bundle.video_output_path is None
