"""#1664 随机边缘裁剪降重功能测试"""

from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path
from unittest.mock import MagicMock, call, patch

import pytest

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "apps" / "worker"))
sys.path.insert(0, str(ROOT / "apps" / "api"))
sys.path.insert(0, str(ROOT / "packages"))


from video_processing.ffmpeg_utils import random_edge_crop


class TestRandomEdgeCropBasic:
    """基本功能测试"""

    def test_returns_input_path_when_output_none(self, tmp_path):
        """output_path=None 时覆盖原文件并返回 input_path"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        fake_info = {"width": 1920, "height": 1080, "duration": 10, "fps": 30}
        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg"),
        ):
            result = random_edge_crop(input_file)

        assert result == input_file

    def test_returns_output_path_when_specified(self, tmp_path):
        """指定 output_path 时返回该路径"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")
        output_file = tmp_path / "output.mp4"

        fake_info = {"width": 1920, "height": 1080, "duration": 10, "fps": 30}
        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg"),
        ):
            result = random_edge_crop(input_file, output_file)

        assert result == output_file

    def test_skip_when_invalid_resolution(self, tmp_path):
        """无法获取有效分辨率时跳过裁剪"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        fake_info = {"width": 0, "height": 0, "duration": 10, "fps": 30}
        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg") as mock_ffmpeg,
        ):
            result = random_edge_crop(input_file)

        assert result == input_file
        mock_ffmpeg.assert_not_called()


class TestRandomEdgeCropFFmpeg:
    """FFmpeg 调用参数验证"""

    def test_ffmpeg_crop_and_scale_filter(self, tmp_path):
        """生成的 ffmpeg 滤镜包含 crop + scale"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        # 固定随机值以便验证
        fake_info = {"width": 1000, "height": 1000, "duration": 10, "fps": 30}

        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg") as mock_ffmpeg,
            patch("random.uniform", side_effect=[0.03, 0.03, 0.03, 0.03]),
        ):
            random_edge_crop(input_file)

        mock_ffmpeg.assert_called_once()
        cmd = mock_ffmpeg.call_args[0][0]
        # 找到 -vf 参数
        vf_idx = cmd.index("-vf")
        vf_value = cmd[vf_idx + 1]
        assert "crop=" in vf_value
        assert "scale=1000:1000" in vf_value

    def test_crop_amounts_within_range(self, tmp_path):
        """裁剪量在 2%~5% 范围内"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        fake_info = {"width": 1000, "height": 1000, "duration": 10, "fps": 30}

        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg") as mock_ffmpeg,
            patch("random.uniform", side_effect=[0.02, 0.05, 0.02, 0.05]),
        ):
            random_edge_crop(input_file)

        cmd = mock_ffmpeg.call_args[0][0]
        vf_idx = cmd.index("-vf")
        vf_value = cmd[vf_idx + 1]
        # crop_top=20, crop_bottom=50, crop_left=20, crop_right=50
        # new_w = 1000-20-50 = 930, new_h = 1000-20-50 = 930
        # x_offset = 20, y_offset = 20
        assert "crop=930:930:20:20" in vf_value

    def test_uses_libx264_codec(self, tmp_path):
        """使用 libx264 编码"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        fake_info = {"width": 1920, "height": 1080, "duration": 10, "fps": 30}
        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg") as mock_ffmpeg,
        ):
            random_edge_crop(input_file)

        cmd = mock_ffmpeg.call_args[0][0]
        assert "-c:v" in cmd
        assert cmd[cmd.index("-c:v") + 1] == "libx264"


class TestRandomEdgeCropErrorHandling:
    """错误处理测试"""

    def test_ffmpeg_failure_raises_exception(self, tmp_path):
        """ffmpeg 失败时抛出异常"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        fake_info = {"width": 1920, "height": 1080, "duration": 10, "fps": 30}
        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch(
                "video_processing.ffmpeg_utils.run_ffmpeg",
                side_effect=subprocess.CalledProcessError(1, "ffmpeg"),
            ),
        ):
            with pytest.raises(subprocess.CalledProcessError):
                random_edge_crop(input_file)

    def test_probe_failure_propagates(self, tmp_path):
        """probe_video_info 失败时异常传播"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        with patch(
            "video_processing.ffmpeg_utils.probe_video_info",
            side_effect=RuntimeError("probe failed"),
        ):
            with pytest.raises(RuntimeError, match="probe failed"):
                random_edge_crop(input_file)


class TestRandomEdgeCropEvenDimensions:
    """偶数尺寸处理测试"""

    def test_odd_crop_dimensions_adjusted_to_even(self, tmp_path):
        """裁剪后尺寸为奇数时自动调整为偶数"""
        input_file = tmp_path / "input.mp4"
        input_file.write_bytes(b"fake video data")

        # 1000 - 3 (top) - 4 (bottom) = 993 → 调整为 992
        # 1000 - 3 (left) - 4 (right) = 993 → 调整为 992
        fake_info = {"width": 1000, "height": 1000, "duration": 10, "fps": 30}

        with (
            patch("video_processing.ffmpeg_utils.probe_video_info", return_value=fake_info),
            patch("video_processing.ffmpeg_utils.run_ffmpeg") as mock_ffmpeg,
            # side_effect 控制 uniform 返回值
            # top: 0.003*1000=3, bottom: 0.004*1000=4, left: 0.003*1000=3, right: 0.004*1000=4
        ):
            # 使用自定义 uniform 返回特定值
            def fake_uniform(low, high):
                # 返回特定百分比使得裁剪后尺寸为奇数
                # 我们需要 crop_top=3, crop_bottom=4, crop_left=3, crop_right=4
                return 0.0035  # 近似值

            # 更简单的方式：直接 mock int(H * random.uniform(...)) 的结果
            # 但我们直接测试最终 crop 滤镜即可
            with patch("random.uniform", side_effect=[0.021, 0.022, 0.021, 0.022]):
                random_edge_crop(input_file)

        cmd = mock_ffmpeg.call_args[0][0]
        vf_idx = cmd.index("-vf")
        vf_value = cmd[vf_idx + 1]
        # 提取 crop 参数并验证都是偶数
        import re

        crop_match = re.search(r"crop=(\d+):(\d+)", vf_value)
        assert crop_match
        crop_w = int(crop_match.group(1))
        crop_h = int(crop_match.group(2))
        assert crop_w % 2 == 0, f"crop width {crop_w} should be even"
        assert crop_h % 2 == 0, f"crop height {crop_h} should be even"
