"""
模板编辑器 Schema 验证测试.

覆盖 ExportUpdateRequest 等带 validator 的 Schema.
纯数据 model 不写单测（无业务逻辑）。
"""

from __future__ import annotations

import pytest
from app.api.routes.templates_editor.schemas import (
    ExportUpdateRequest,
)


class TestExportUpdateRequestResolution:
    """resolution 字段验证."""

    def test_valid_1080p(self):
        req = ExportUpdateRequest(resolution="1920x1080")
        assert req.resolution == "1920x1080"

    def test_valid_portrait(self):
        req = ExportUpdateRequest(resolution="1080x1920")
        assert req.resolution == "1080x1920"

    def test_valid_square(self):
        req = ExportUpdateRequest(resolution="1080x1080")
        assert req.resolution == "1080x1080"

    def test_valid_min(self):
        req = ExportUpdateRequest(resolution="100x100")
        assert req.resolution == "100x100"

    def test_valid_max(self):
        req = ExportUpdateRequest(resolution="4096x4096")
        assert req.resolution == "4096x4096"

    def test_none_is_valid(self):
        req = ExportUpdateRequest()
        assert req.resolution is None

    def test_invalid_format_no_x(self):
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="19201080")

    def test_invalid_format_letters(self):
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="abcxdef")

    def test_invalid_format_empty(self):
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="")

    def test_invalid_format_upper_x(self):
        """大写 X 不匹配正则"""
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="1920X1080")

    def test_too_small_width(self):
        with pytest.raises(ValueError, match="过小"):
            ExportUpdateRequest(resolution="50x1080")

    def test_too_small_height(self):
        with pytest.raises(ValueError, match="过小"):
            ExportUpdateRequest(resolution="1920x50")

    def test_too_large_width(self):
        with pytest.raises(ValueError, match="过大"):
            ExportUpdateRequest(resolution="5000x1080")

    def test_too_large_height(self):
        with pytest.raises(ValueError, match="过大"):
            ExportUpdateRequest(resolution="1920x5000")

    def test_extra_chars_after(self):
        """后面多字符也不匹配"""
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="1920x1080p")

    def test_extra_chars_before(self):
        with pytest.raises(ValueError, match="分辨率格式错误"):
            ExportUpdateRequest(resolution="fhd1920x1080")


class TestExportUpdateRequestFormat:
    """format 字段验证."""

    def test_valid_mp4(self):
        req = ExportUpdateRequest(format="mp4")
        assert req.format == "mp4"

    def test_valid_mov(self):
        req = ExportUpdateRequest(format="mov")
        assert req.format == "mov"

    def test_none_is_valid(self):
        req = ExportUpdateRequest()
        assert req.format is None

    def test_invalid_avi(self):
        with pytest.raises(ValueError, match="无效格式"):
            ExportUpdateRequest(format="avi")

    def test_invalid_empty(self):
        with pytest.raises(ValueError, match="无效格式"):
            ExportUpdateRequest(format="")

    def test_invalid_upper(self):
        with pytest.raises(ValueError, match="无效格式"):
            ExportUpdateRequest(format="MP4")


class TestExportUpdateRequestQualityPreset:
    """quality_preset 字段验证."""

    @pytest.mark.parametrize("preset", ["ultra_fast", "fast", "balanced", "high", "best"])
    def test_valid_presets(self, preset):
        req = ExportUpdateRequest(quality_preset=preset)
        assert req.quality_preset == preset

    def test_none_is_valid(self):
        req = ExportUpdateRequest()
        assert req.quality_preset is None

    def test_invalid_preset(self):
        with pytest.raises(ValueError, match="无效质量预设"):
            ExportUpdateRequest(quality_preset="ultra")

    def test_invalid_empty(self):
        with pytest.raises(ValueError, match="无效质量预设"):
            ExportUpdateRequest(quality_preset="")


class TestExportUpdateRequestFps:
    """fps 字段范围验证（由 Field ge/le 控制）."""

    def test_valid_30(self):
        req = ExportUpdateRequest(fps=30)
        assert req.fps == 30

    def test_valid_min(self):
        req = ExportUpdateRequest(fps=15)
        assert req.fps == 15

    def test_valid_max(self):
        req = ExportUpdateRequest(fps=60)
        assert req.fps == 60

    def test_below_min(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(fps=10)

    def test_above_max(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(fps=120)

    def test_none_is_valid(self):
        req = ExportUpdateRequest()
        assert req.fps is None


class TestExportUpdateRequestBitrate:
    """码率字段范围验证."""

    def test_video_bitrate_valid(self):
        req = ExportUpdateRequest(video_bitrate=5000)
        assert req.video_bitrate == 5000

    def test_video_bitrate_min(self):
        req = ExportUpdateRequest(video_bitrate=1000)
        assert req.video_bitrate == 1000

    def test_video_bitrate_max(self):
        req = ExportUpdateRequest(video_bitrate=20000)
        assert req.video_bitrate == 20000

    def test_video_bitrate_below_min(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(video_bitrate=500)

    def test_video_bitrate_above_max(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(video_bitrate=50000)

    def test_audio_bitrate_valid(self):
        req = ExportUpdateRequest(audio_bitrate=128)
        assert req.audio_bitrate == 128

    def test_audio_bitrate_min(self):
        req = ExportUpdateRequest(audio_bitrate=64)
        assert req.audio_bitrate == 64

    def test_audio_bitrate_max(self):
        req = ExportUpdateRequest(audio_bitrate=320)
        assert req.audio_bitrate == 320

    def test_audio_bitrate_below_min(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(audio_bitrate=32)

    def test_audio_bitrate_above_max(self):
        with pytest.raises(ValueError):
            ExportUpdateRequest(audio_bitrate=512)


class TestExportUpdateRequestWatermark:
    """水印字段."""

    def test_watermark_enabled(self):
        req = ExportUpdateRequest(watermark_enabled=True, watermark_text="hello")
        assert req.watermark_enabled is True
        assert req.watermark_text == "hello"

    def test_watermark_disabled(self):
        req = ExportUpdateRequest(watermark_enabled=False)
        assert req.watermark_enabled is False

    def test_watermark_default_none(self):
        req = ExportUpdateRequest()
        assert req.watermark_enabled is None
        assert req.watermark_text is None


class TestExportUpdateRequestCombined:
    """组合字段验证."""

    def test_full_valid(self):
        req = ExportUpdateRequest(
            resolution="1920x1080",
            fps=30,
            video_bitrate=8000,
            audio_bitrate=128,
            format="mp4",
            quality_preset="balanced",
            watermark_enabled=True,
            watermark_text="test",
        )
        assert req.resolution == "1920x1080"
        assert req.fps == 30
        assert req.format == "mp4"
        assert req.quality_preset == "balanced"

    def test_partial_update(self):
        """只更新部分字段，其余为 None"""
        req = ExportUpdateRequest(fps=24)
        assert req.fps == 24
        assert req.resolution is None
        assert req.format is None
        assert req.quality_preset is None
