"""media_validation 媒体文件校验单测."""

import pytest
from domain.media_validation import (
    MIN_AUDIO_FILE_SIZE,
    MIN_IMAGE_FILE_SIZE,
    MIN_VIDEO_FILE_SIZE,
    SUPPORTED_VIDEO_CODECS,
    is_valid_media,
    safe_parse_fps,
)

# ── 常量测试 ─────────────────────────────────────────────────────────────────


class TestConstants:
    """模块常量"""

    def test_min_sizes(self):
        assert MIN_VIDEO_FILE_SIZE == 1024
        assert MIN_AUDIO_FILE_SIZE == 100
        assert MIN_IMAGE_FILE_SIZE == 100

    def test_supported_codecs_is_frozenset(self):
        assert isinstance(SUPPORTED_VIDEO_CODECS, frozenset)

    def test_supported_codecs_includes_common(self):
        assert "h264" in SUPPORTED_VIDEO_CODECS
        assert "hevc" in SUPPORTED_VIDEO_CODECS
        assert "vp9" in SUPPORTED_VIDEO_CODECS
        assert "av1" in SUPPORTED_VIDEO_CODECS
        assert "mpeg4" in SUPPORTED_VIDEO_CODECS
        assert "prores" in SUPPORTED_VIDEO_CODECS

    def test_supported_codecs_count(self):
        assert len(SUPPORTED_VIDEO_CODECS) >= 20


# ── safe_parse_fps ───────────────────────────────────────────────────────────


class TestSafeParseFps:
    """safe_parse_fps 函数"""

    def test_simple_decimal(self):
        assert safe_parse_fps("30.0") == 30.0

    def test_integer_string(self):
        assert safe_parse_fps("24") == 24.0

    def test_fraction_format(self):
        assert abs(safe_parse_fps("30000/1001") - 29.97) < 0.01

    def test_simple_fraction(self):
        assert safe_parse_fps("30/1") == 30.0

    def test_24fps_fraction(self):
        assert safe_parse_fps("24/1") == 24.0

    def test_60fps_fraction(self):
        assert safe_parse_fps("60000/1001") == pytest.approx(59.94, abs=0.01)

    def test_zero_denominator_returns_zero(self):
        assert safe_parse_fps("30/0") == 0.0

    def test_empty_string_returns_zero(self):
        assert safe_parse_fps("") == 0.0

    def test_invalid_string_returns_zero(self):
        assert safe_parse_fps("invalid") == 0.0

    def test_none_numerator_fraction(self):
        assert safe_parse_fps("abc/1001") == 0.0

    def test_negative_fps(self):
        assert safe_parse_fps("-30") == -30.0

    def test_very_high_fps(self):
        assert safe_parse_fps("240/1") == 240.0

    def test_multiple_slashes(self):
        # 只按第一个 / 分割
        # "30/1/2" → num="30", den="1/2" → float("1/2") 抛异常 → 返回 0
        assert safe_parse_fps("30/1/2") == 0.0

    def test_float_fraction(self):
        result = safe_parse_fps("29.97/1")
        assert result == pytest.approx(29.97)

    def test_zero_fps(self):
        assert safe_parse_fps("0") == 0.0

    def test_zero_numerator(self):
        assert safe_parse_fps("0/1000") == 0.0


# ── is_valid_media - video ───────────────────────────────────────────────────


class TestIsValidMediaVideo:
    """is_valid_media 视频校验"""

    def test_valid_video(self):
        metadata = {
            "size_bytes": 1024 * 1024,  # 1MB
            "duration": 10.0,
            "codec": "h264",
            "width": 1920,
            "height": 1080,
        }
        assert is_valid_media(metadata, "video") is True

    def test_small_file_invalid(self):
        metadata = {"size_bytes": 100, "duration": 10.0}
        assert is_valid_media(metadata, "video") is False

    def test_exact_min_size_valid(self):
        metadata = {"size_bytes": MIN_VIDEO_FILE_SIZE, "duration": 1.0}
        assert is_valid_media(metadata, "video") is True

    def test_zero_duration_invalid(self):
        metadata = {"size_bytes": 1024 * 1024, "duration": 0}
        assert is_valid_media(metadata, "video") is False

    def test_negative_duration_invalid(self):
        metadata = {"size_bytes": 1024 * 1024, "duration": -1.0}
        assert is_valid_media(metadata, "video") is False

    def test_unsupported_codec_still_valid(self):
        # 非白名单编码仍允许通过（不做严格拦截）
        metadata = {
            "size_bytes": 1024 * 1024,
            "duration": 10.0,
            "codec": "unknown_codec_xyz",
        }
        assert is_valid_media(metadata, "video") is True

    def test_empty_codec_valid(self):
        metadata = {"size_bytes": 1024 * 1024, "duration": 10.0, "codec": ""}
        assert is_valid_media(metadata, "video") is True

    def test_no_codec_valid(self):
        metadata = {"size_bytes": 1024 * 1024, "duration": 10.0}
        assert is_valid_media(metadata, "video") is True

    def test_hevc_codec_valid(self):
        metadata = {
            "size_bytes": 1024 * 1024,
            "duration": 10.0,
            "codec": "hevc",
        }
        assert is_valid_media(metadata, "video") is True

    def test_codec_case_insensitive(self):
        metadata = {
            "size_bytes": 1024 * 1024,
            "duration": 10.0,
            "codec": "H264",
        }
        assert is_valid_media(metadata, "video") is True

    def test_missing_size_invalid(self):
        metadata = {"duration": 10.0}
        assert is_valid_media(metadata, "video") is False

    def test_missing_duration_invalid(self):
        metadata = {"size_bytes": 1024 * 1024}
        assert is_valid_media(metadata, "video") is False

    def test_empty_metadata_invalid(self):
        assert is_valid_media({}, "video") is False


# ── is_valid_media - audio ───────────────────────────────────────────────────


class TestIsValidMediaAudio:
    """is_valid_media 音频校验"""

    def test_valid_audio(self):
        metadata = {"size_bytes": 1024, "duration": 30.0, "codec": "aac"}
        assert is_valid_media(metadata, "audio") is True

    def test_small_audio_invalid(self):
        metadata = {"size_bytes": 50, "duration": 30.0}
        assert is_valid_media(metadata, "audio") is False

    def test_exact_min_size_valid(self):
        metadata = {"size_bytes": MIN_AUDIO_FILE_SIZE, "duration": 1.0}
        assert is_valid_media(metadata, "audio") is True

    def test_zero_duration_invalid(self):
        metadata = {"size_bytes": 1024, "duration": 0}
        assert is_valid_media(metadata, "audio") is False

    def test_negative_duration_invalid(self):
        metadata = {"size_bytes": 1024, "duration": -5.0}
        assert is_valid_media(metadata, "audio") is False

    def test_empty_metadata_invalid(self):
        assert is_valid_media({}, "audio") is False

    def test_very_short_audio_valid(self):
        metadata = {"size_bytes": 200, "duration": 0.5}
        assert is_valid_media(metadata, "audio") is True


# ── is_valid_media - image ───────────────────────────────────────────────────


class TestIsValidMediaImage:
    """is_valid_media 图片校验"""

    def test_valid_image(self):
        metadata = {"size_bytes": 1024, "width": 1920, "height": 1080}
        assert is_valid_media(metadata, "image") is True

    def test_small_image_invalid(self):
        metadata = {"size_bytes": 50, "width": 1920, "height": 1080}
        assert is_valid_media(metadata, "image") is False

    def test_exact_min_size_valid(self):
        metadata = {
            "size_bytes": MIN_IMAGE_FILE_SIZE,
            "width": 100,
            "height": 100,
        }
        assert is_valid_media(metadata, "image") is True

    def test_zero_width_invalid(self):
        metadata = {"size_bytes": 1024, "width": 0, "height": 1080}
        assert is_valid_media(metadata, "image") is False

    def test_zero_height_invalid(self):
        metadata = {"size_bytes": 1024, "width": 1920, "height": 0}
        assert is_valid_media(metadata, "image") is False

    def test_negative_width_invalid(self):
        metadata = {"size_bytes": 1024, "width": -1, "height": 1080}
        assert is_valid_media(metadata, "image") is False

    def test_small_image_valid(self):
        metadata = {"size_bytes": 200, "width": 10, "height": 10}
        assert is_valid_media(metadata, "image") is True

    def test_missing_width_invalid(self):
        metadata = {"size_bytes": 1024, "height": 1080}
        assert is_valid_media(metadata, "image") is False

    def test_missing_height_invalid(self):
        metadata = {"size_bytes": 1024, "width": 1920}
        assert is_valid_media(metadata, "image") is False

    def test_empty_metadata_invalid(self):
        assert is_valid_media({}, "image") is False


# ── is_valid_media - edge cases ─────────────────────────────────────────────


class TestIsValidMediaEdgeCases:
    """is_valid_media 边界情况"""

    def test_invalid_media_type(self):
        metadata = {"size_bytes": 1024, "duration": 10.0}
        assert is_valid_media(metadata, "document") is False

    def test_empty_media_type(self):
        metadata = {"size_bytes": 1024}
        assert is_valid_media(metadata, "") is False

    def test_string_size_converted(self):
        metadata = {"size_bytes": "2048", "duration": "5.0"}
        assert is_valid_media(metadata, "video") is True

    def test_video_size_as_string(self):
        metadata = {"size_bytes": "1000000", "duration": "30"}
        assert is_valid_media(metadata, "video") is True

    def test_invalid_size_string_raises(self):
        # int("abc") 会抛 ValueError
        metadata = {"size_bytes": "abc", "duration": 10.0}
        with pytest.raises(ValueError):
            is_valid_media(metadata, "video")

    def test_none_size_raises(self):
        # int(None) 会抛 TypeError
        metadata = {"size_bytes": None, "duration": 10.0}
        with pytest.raises(TypeError):
            is_valid_media(metadata, "video")
