"""Tests for section builder — SectionDef, build_fx_chain, effect alias mapping."""

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parents[1]))

import pytest
from src.core.schema import SectionDef, PluginDef


class TestSectionDef:
    """Test SectionDef dataclass."""

    def test_section_def_instantiation(self):
        """SectionDef creates with name, bars, energy."""
        section = SectionDef(name="chorus", bars=8, energy=0.9)
        assert section.name == "chorus"
        assert section.bars == 8
        assert section.energy == 0.9
        # velocity_mult and vol_mult default to 1.0 (not derived from energy)
        assert section.velocity_mult == 1.0
        assert section.vol_mult == 1.0

    def test_section_def_default_energy(self):
        """SectionDef defaults energy to 0.5, velocity_mult/vol_mult to 1.0."""
        section = SectionDef(name="verse", bars=8)
        assert section.energy == 0.5
        assert section.velocity_mult == 1.0
        assert section.vol_mult == 1.0

    def test_section_def_custom_mults(self):
        """SectionDef accepts custom velocity_mult and vol_mult via __init__ args."""
        section = SectionDef(
            name="intro", bars=4, energy=0.3,
            velocity_mult=0.4, vol_mult=0.6
        )
        assert section.velocity_mult == 0.4
        assert section.vol_mult == 0.6


class TestVST3Effects:
    """Test VST3 premium plugin mappings."""

    def test_vst3_effects_defined(self):
        """_VST3_EFFECTS maps effect names to VST3 plugins."""
        from scripts.compose import _VST3_EFFECTS
        assert "Pro-Q 3" in _VST3_EFFECTS
        assert "Pro-C 2" in _VST3_EFFECTS
        assert "Pro-R 2" in _VST3_EFFECTS
        assert "Timeless 3" in _VST3_EFFECTS

    def test_fruity_eq_maps_to_proq3(self):
        """Fruity Parametric EQ 2 → FabFilter Pro-Q 3 via normalization."""
        from scripts.compose import _VST3_EFFECTS
        # Fruity Parametric EQ 2 normalizes to Pro-Q 3
        registry_key, filename = _VST3_EFFECTS["Pro-Q 3"]
        assert registry_key == "Pro-Q_3"
        assert filename == "FabFilter"

    def test_fruity_compressor_maps_to_proc2(self):
        """Fruity Compressor → FabFilter Pro-C 2 via normalization."""
        from scripts.compose import _VST3_EFFECTS
        registry_key, filename = _VST3_EFFECTS["Pro-C 2"]
        assert registry_key == "Pro-C_2"
        assert filename == "FabFilter"

    def test_pro_r_maps_to_pror2(self):
        """Pro-R 2 → FabFilter Pro-R 2."""
        from scripts.compose import _VST3_EFFECTS
        registry_key, filename = _VST3_EFFECTS["Pro-R 2"]
        assert registry_key == "Pro-R_2"
        assert filename == "FabFilter"

    def test_unknown_effect_returns_none(self):
        """Unknown effect names return no VST3 info."""
        from scripts.compose import _VST3_EFFECTS
        assert _VST3_EFFECTS.get("Some Unknown Plugin") is None


class TestBuildFxChain:
    """Test build_fx_chain function."""

    def test_build_fx_chain_drums(self):
        """build_fx_chain returns PluginDef list for drums role."""
        from scripts.compose import build_fx_chain

        genre_config = {
            "mix": {
                "per_role": {
                    "drums": {
                        "effects": ["Fruity Parametric EQ 2", "Fruity Compressor"],
                    }
                }
            }
        }
        plugins = build_fx_chain("drums", genre_config, [])
        assert len(plugins) == 2
        # Pro-Q 3 via alias
        assert plugins[0].name in ("Pro-Q_3", "FabFilter_Pro-Q_3")
        assert plugins[0].path in ("FabFilter", "FabFilter Pro-Q 3.vst3")
        # Fruity Compressor → Pro-C 2
        assert plugins[1].name in ("Pro-C_2", "FabFilter_Pro-C_2")

    def test_build_fx_chain_bass(self):
        """build_fx_chain returns PluginDef list for bass role."""
        from scripts.compose import build_fx_chain

        genre_config = {
            "mix": {
                "per_role": {
                    "bass": {
                        "effects": ["Fruity Parametric EQ 2", "Saturn 2"],
                    }
                }
            }
        }
        plugins = build_fx_chain("bass", genre_config, [])
        assert len(plugins) == 2
        # Saturn 2 → FabFilter Saturn 2
        assert "Saturn" in plugins[1].name

    def test_build_fx_chain_empty_effects(self):
        """build_fx_chain returns empty list when no effects configured."""
        from scripts.compose import build_fx_chain

        genre_config = {"mix": {"per_role": {}}}
        plugins = build_fx_chain("drums", genre_config, [])
        assert plugins == []

    def test_build_fx_chain_unknown_effect_uses_name(self):
        """Unknown effect names are used as-is."""
        from scripts.compose import build_fx_chain

        genre_config = {
            "mix": {
                "per_role": {
                    "lead": {
                        "effects": ["Some Unknown FX"],
                    }
                }
            }
        }
        plugins = build_fx_chain("lead", genre_config, [])
        # Unknown effects are skipped (not added to plugins)
        assert len(plugins) == 0


class TestInstrumentPlugins:
    """Test instrument plugin helpers (Serum 2, Omnisphere)."""

    def test_serum2_plugin_def(self):
        """serum2() returns PluginDef with registry key name."""
        from scripts.compose import serum2

        plugin = serum2()
        assert plugin.name == "Serum2"
        assert plugin.path == "Serum2.vst3"
        assert plugin.index == 0

    def test_omnisphere_plugin_def(self):
        """omnisphere() returns PluginDef with registry key name."""
        from scripts.compose import omnisphere

        plugin = omnisphere()
        assert plugin.name == "Omnisphere"
        assert plugin.path == "Omnisphere.vst3"
        assert plugin.index == 0


class TestCreateReturnTracks:
    """Test create_return_tracks function."""

    def test_create_return_tracks_returns_two(self):
        """create_return_tracks returns [Reverb, Delay] tracks."""
        from scripts.compose import create_return_tracks

        tracks = create_return_tracks()
        assert len(tracks) == 2
        assert tracks[0].name == "Reverb"
        assert tracks[1].name == "Delay"

    def test_reverb_track_has_pro_r2(self):
        """Reverb return track has FabFilter Pro-R 2 plugin."""
        from scripts.compose import create_return_tracks

        tracks = create_return_tracks()
        reverb = tracks[0]
        assert len(reverb.plugins) == 1
        assert "FabFilter" in reverb.plugins[0].name
        assert reverb.plugins[0].path in ("FabFilter", "FabFilter_Pro_R_2.vst3")

    def test_delay_track_has_timeless3(self):
        """Delay return track has FabFilter Timeless 3 plugin."""
        from scripts.compose import create_return_tracks

        tracks = create_return_tracks()
        delay = tracks[1]
        assert len(delay.plugins) == 1
        assert "Timeless" in delay.plugins[0].name
        assert delay.plugins[0].path in ("FabFilter", "FabFilter_Timeless_3.vst3")

    def test_return_tracks_have_volume_0_7(self):
        """Return tracks have volume 0.7."""
        from scripts.compose import create_return_tracks

        tracks = create_return_tracks()
        for t in tracks:
            assert t.volume == 0.7