"""多轨道混音单元测试 - 配置解析等纯逻辑."""

from __future__ import annotations

import pytest
from video_processing.multi_track_mixer import (
    DEFAULT_VOLUMES,
    MAX_AUDIO_TRACKS,
    TRACK_TYPE_AMBIENT,
    TRACK_TYPE_BGM,
    TRACK_TYPE_MAIN,
    TRACK_TYPE_SFX,
    TRACK_TYPE_VOICEOVER,
    AudioTrack,
    MultiTrackMixConfig,
)


class TestConstants:
    """常量测试."""

    def test_track_types(self):
        """5种轨道类型."""
        assert TRACK_TYPE_MAIN == "main"
        assert TRACK_TYPE_BGM == "bgm"
        assert TRACK_TYPE_VOICEOVER == "voiceover"
        assert TRACK_TYPE_SFX == "sfx"
        assert TRACK_TYPE_AMBIENT == "ambient"

    def test_default_volumes(self):
        """5种默认音量."""
        assert len(DEFAULT_VOLUMES) == 5
        assert DEFAULT_VOLUMES[TRACK_TYPE_MAIN] == 1.0
        assert DEFAULT_VOLUMES[TRACK_TYPE_BGM] == 0.3
        assert DEFAULT_VOLUMES[TRACK_TYPE_VOICEOVER] == 1.0
        assert DEFAULT_VOLUMES[TRACK_TYPE_SFX] == 0.7
        assert DEFAULT_VOLUMES[TRACK_TYPE_AMBIENT] == 0.2

    def test_max_tracks(self):
        """最大轨道数."""
        assert MAX_AUDIO_TRACKS == 8


class TestAudioTrackDefaults:
    """AudioTrack 默认值测试."""

    def test_default_values(self):
        """默认值正确."""
        track = AudioTrack(track_id="t1", track_type="bgm", audio_path="/a.mp3")
        assert track.track_id == "t1"
        assert track.track_type == "bgm"
        assert track.audio_path == "/a.mp3"
        assert track.volume == 1.0
        assert track.fade_in == 0.0
        assert track.fade_out == 0.0
        assert track.start_time == 0.0
        assert track.duration == 0.0
        assert track.enabled is True


class TestAudioTrackFromDict:
    """AudioTrack.from_dict 解析测试."""

    def test_basic_parsing(self):
        """基本解析."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "bgm",
                "audio_path": "/bgm.mp3",
            }
        )
        assert track.track_id == "t1"
        assert track.track_type == "bgm"
        assert track.audio_path == "/bgm.mp3"

    def test_default_volume_by_type_bgm(self):
        """bgm默认音量0.3."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "bgm",
                "audio_path": "/a.mp3",
            }
        )
        assert track.volume == 0.3

    def test_default_volume_by_type_sfx(self):
        """sfx默认音量0.7."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "sfx",
                "audio_path": "/a.mp3",
            }
        )
        assert track.volume == 0.7

    def test_default_volume_unknown_type(self):
        """未知类型默认音量1.0."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "unknown_type",
                "audio_path": "/a.mp3",
            }
        )
        assert track.volume == 1.0

    def test_custom_volume(self):
        """自定义音量."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "bgm",
                "audio_path": "/a.mp3",
                "volume": 0.5,
            }
        )
        assert track.volume == 0.5

    def test_volume_clamped_high(self):
        """音量上限钳制."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "bgm",
                "audio_path": "/a.mp3",
                "volume": 3.0,
            }
        )
        assert track.volume == 2.0

    def test_volume_clamped_low(self):
        """音量下限钳制."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "volume": -1.0,
            }
        )
        assert track.volume == 0.0

    def test_volume_invalid_falls_back(self):
        """无效音量回退到类型默认值."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "track_type": "bgm",
                "audio_path": "/a.mp3",
                "volume": "not_a_number",
            }
        )
        assert track.volume == 0.3

    def test_fade_in(self):
        """淡入时长."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "fade_in": 2.5,
            }
        )
        assert track.fade_in == 2.5

    def test_fade_negative_clamped(self):
        """负淡入钳制到0."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "fade_in": -1.0,
                "fade_out": -2.0,
            }
        )
        assert track.fade_in == 0.0
        assert track.fade_out == 0.0

    def test_start_time(self):
        """开始时间."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "start_time": 5.5,
            }
        )
        assert track.start_time == 5.5

    def test_start_time_negative_clamped(self):
        """负开始时间钳制到0."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "start_time": -3.0,
            }
        )
        assert track.start_time == 0.0

    def test_disabled_track(self):
        """禁用轨道."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "enabled": False,
            }
        )
        assert track.enabled is False

    def test_invalid_fade_in_falls_back(self):
        """无效淡入值回退到0."""
        track = AudioTrack.from_dict(
            {
                "track_id": "t1",
                "audio_path": "/a.mp3",
                "fade_in": "fast",
            }
        )
        assert track.fade_in == 0.0


class TestMultiTrackMixConfigDefaults:
    """MultiTrackMixConfig 默认值测试."""

    def test_default_values(self):
        """默认值正确."""
        config = MultiTrackMixConfig()
        assert config.tracks == []
        assert config.master_volume == 1.0
        assert config.normalize is True
        assert config.max_output_volume == 1.5


class TestMultiTrackMixConfigFromConfigDict:
    """MultiTrackMixConfig.from_config_dict 测试."""

    def test_none_returns_default(self):
        """None返回默认配置."""
        config = MultiTrackMixConfig.from_config_dict(None)
        assert config.tracks == []
        assert config.master_volume == 1.0

    def test_empty_dict_returns_default(self):
        """空dict返回默认."""
        config = MultiTrackMixConfig.from_config_dict({})
        assert config.tracks == []

    def test_single_track(self):
        """单轨道."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": [
                    {
                        "track_id": "bgm1",
                        "track_type": "bgm",
                        "audio_path": "/bgm.mp3",
                    },
                ],
            }
        )
        assert len(config.tracks) == 1
        assert config.tracks[0].track_id == "bgm1"

    def test_multiple_tracks(self):
        """多轨道."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": [
                    {"track_id": "t1", "track_type": "bgm", "audio_path": "/a.mp3"},
                    {"track_id": "t2", "track_type": "sfx", "audio_path": "/b.mp3"},
                ],
            }
        )
        assert len(config.tracks) == 2

    def test_skips_disabled_tracks(self):
        """跳过禁用轨道."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": [
                    {"track_id": "t1", "audio_path": "/a.mp3", "enabled": True},
                    {"track_id": "t2", "audio_path": "/b.mp3", "enabled": False},
                ],
            }
        )
        assert len(config.tracks) == 1
        assert config.tracks[0].track_id == "t1"

    def test_skips_no_audio_path(self):
        """跳过无audio_path的轨道."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": [
                    {"track_id": "t1", "audio_path": "/a.mp3"},
                    {"track_id": "t2", "audio_path": ""},
                    {"track_id": "t3"},
                ],
            }
        )
        assert len(config.tracks) == 1

    def test_master_volume(self):
        """主音量."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "master_volume": 0.8,
                "tracks": [{"track_id": "t1", "audio_path": "/a.mp3"}],
            }
        )
        assert config.master_volume == 0.8

    def test_master_volume_clamped(self):
        """主音量边界钳制."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "master_volume": 5.0,
                "tracks": [{"track_id": "t1", "audio_path": "/a.mp3"}],
            }
        )
        assert config.master_volume == 2.0

    def test_normalize_disabled(self):
        """禁用归一化."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "normalize": False,
                "tracks": [{"track_id": "t1", "audio_path": "/a.mp3"}],
            }
        )
        assert config.normalize is False

    def test_tracks_not_list_ignored(self):
        """tracks不是列表时忽略."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": "not_a_list",
            }
        )
        assert config.tracks == []

    def test_non_dict_track_skipped(self):
        """非dict轨道跳过."""
        config = MultiTrackMixConfig.from_config_dict(
            {
                "tracks": [
                    {"track_id": "t1", "audio_path": "/a.mp3"},
                    "not_a_dict",
                ],
            }
        )
        assert len(config.tracks) == 1


class TestHasEffect:
    """has_effect 属性测试."""

    def test_no_tracks_no_effect(self):
        """无轨道无效果."""
        config = MultiTrackMixConfig()
        assert config.has_effect is False

    def test_with_tracks_has_effect(self):
        """有轨道有效果."""
        config = MultiTrackMixConfig(
            tracks=[
                AudioTrack(track_id="t1", track_type="bgm", audio_path="/a.mp3"),
            ]
        )
        assert config.has_effect is True

    def test_disabled_tracks_no_effect(self):
        """所有轨道都禁用无效果."""
        config = MultiTrackMixConfig(
            tracks=[
                AudioTrack(track_id="t1", track_type="bgm", audio_path="/a.mp3", enabled=False),
            ]
        )
        assert config.has_effect is False
