using AlienAttack.MonoGame.Things.Bullets;
using AlienAttack.MonoGame.Things.Items;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;

namespace AlienAttack.MonoGame.Audio;

public sealed class AudioManager
{
    public float MasterVolume { get; set; } = 1f;
    public float SfxVolume { get; set; } = 0.8f;
    public float MusicVolume { get; set; } = 0.7f;

    private readonly Random _random = new(12345);

    // Pools
    private VariantSoundPool _playerGunPool = default!;
    private readonly Dictionary<BulletKind, VariantSoundPool> _playerGunPool2 = [];

    private VariantSoundPool _enemyGunPool = default!;
    private readonly Dictionary<BulletKind, VariantSoundPool> _enemyGunPool2 = [];

    private VariantSoundPool _explosionPool = default!;
    private VariantSoundPool _impactPool = default!;
    private readonly Dictionary<PickupKind, VariantSoundPool> _pickupPool = [];

    // Rate limiters (global caps per category/event)
    private RateLimiter _playerGunLimiter = new(0.06f); // max ~16 plays/sec
    private RateLimiter _enemyGunLimiter = new(0.12f); // max ~8 plays/sec (global for all enemies)
    private RateLimiter _impactLimiter = new(0.04f);

    // Music
    private Song? _currentSong;
    private float _musicDuck = 1f;         // 1.0 = normal, <1 = ducked
    private float _musicDuckTarget = 1f;
    private float _musicDuckSpeed = 6f;    // how fast it moves toward target (bigger = snappier)

    public void LoadContent(ContentManager content)
    {
        // Load SoundEffects once
        LoadPlayerGunPool(content);
        LoadGunPools(content);
        LoadEnemyGunPool(content);
        LoadImpactPool(content);
        LoadExplosionPool(content);

        LoadShieldPickupPool(content);
        LoadAmmoPickupPool(content);
        LoadRocketsPickupPool(content);
        LoadPlasmaPickupPool(content);
    }

    private void LoadPlayerGunPool(ContentManager content)
    {
        var playerGunVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_06_SFRMS_SCIWPNS")
        };

        _playerGunPool = new VariantSoundPool(playerGunVariants, voicesPerVariant: 1, rng: _random);
    }

    private void LoadGunPools(ContentManager content)
    {
        var minigunSmallVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS")
        };

        var minigunLargeVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_06_SFRMS_SCIWPNS")
        };

        // Laser

        //LASRGun_Alien Handgun Fire Light_01_SFRMS_SCIWPNS

        var laserSmallVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_06_SFRMS_SCIWPNS")
        };

        var laserMediumVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_06_SFRMS_SCIWPNS")
        };

        var laserLargeVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_06_SFRMS_SCIWPNS")
        };

        // Plasma

        //GUNAuto_Plasmid Machinegun Single_01_SFRMS_SCIWPNS
        //GUNAuto_Plasmid Machinegun B Single_01_SFRMS_SCIWPNS

        var plasmaSmallVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_06_SFRMS_SCIWPNS")
        };

        var plasmaMediumVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_06_SFRMS_SCIWPNS")
        };

        var plasmaLargeVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_06_SFRMS_SCIWPNS")
        };

        // Proton

        var protonSmallVariants = new[]
       {
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_06_SFRMS_SCIWPNS")
        };

        var protonMediumVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_06_SFRMS_SCIWPNS")
        };

        var protonLargeVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_06_SFRMS_SCIWPNS")
        };

        //GUNAuto_RPU1 Fire_01_SFRMS_SCIWPNS

        _playerGunPool2.Add(BulletKind.MinigunSmall, new VariantSoundPool(minigunSmallVariants, voicesPerVariant: 1, rng: _random));
        //_playerGunPool2.Add(BulletKind.MinigunMedium, new VariantSoundPool(minigunLargeVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.MinigunLarge, new VariantSoundPool(minigunLargeVariants, voicesPerVariant: 1, rng: _random));

        _playerGunPool2.Add(BulletKind.LaserSmall, new VariantSoundPool(laserSmallVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.LaserMedium, new VariantSoundPool(laserMediumVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.LaserLarge, new VariantSoundPool(laserLargeVariants, voicesPerVariant: 1, rng: _random));

        _playerGunPool2.Add(BulletKind.PlasmaSmall, new VariantSoundPool(plasmaSmallVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.PlasmaMedium, new VariantSoundPool(plasmaMediumVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.PlasmaLarge, new VariantSoundPool(plasmaLargeVariants, voicesPerVariant: 1, rng: _random));

        _playerGunPool2.Add(BulletKind.ProtonSmall, new VariantSoundPool(protonSmallVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.ProtonMedium, new VariantSoundPool(protonMediumVariants, voicesPerVariant: 1, rng: _random));
        _playerGunPool2.Add(BulletKind.ProtonLarge, new VariantSoundPool(protonLargeVariants, voicesPerVariant: 1, rng: _random));

    }

    private void LoadEnemyGunPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS"),
        };

        _enemyGunPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
    }

    private void LoadImpactPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_06_SFRMS_SCIWPNS"),
        };

        _impactPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
    }

    private void LoadExplosionPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_06_SFRMS_SCIWPNS")
        };

        _explosionPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
    }

    private void LoadShieldPickupPool(ContentManager content)
    {
        var shieldVariants = new[]
        {
            content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_05_SFRMS_SCIWPNS")
        };

        _pickupPool.Add(PickupKind.Shield, new VariantSoundPool(shieldVariants, voicesPerVariant: 1, rng: _random));
    }

    private void LoadAmmoPickupPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_05_SFRMS_SCIWPNS")
        };

        _pickupPool.Add(PickupKind.Ammo, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
    }

    private void LoadRocketsPickupPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_06_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_07_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_08_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_09_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_10_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_11_SFRMS_SCIWPNS"),
        };

        _pickupPool.Add(PickupKind.Rockets, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
    }

    //SCIMisc_Sci Fi Shotgun Reload_01_SFRMS_SCIWPNS

    private void LoadPlasmaPickupPool(ContentManager content)
    {
        var variants = new[]
        {
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_01_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_02_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_03_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_04_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_05_SFRMS_SCIWPNS"),
            content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_06_SFRMS_SCIWPNS"),
        };

        _pickupPool.Add(PickupKind.Plasma, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
    }

    //GUNMech_Rocket Launcher Reload_01_SFRMS_SCIWPNS

    // Call this once per frame
    public void Update(GameTime gameTime)
    {
        float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

        _playerGunLimiter.Update(dt);
        _enemyGunLimiter.Update(dt);
        _impactLimiter.Update(dt);

        // Smoothly approach the duck target
        _musicDuck = Approach(_musicDuck, _musicDuckTarget, _musicDuckSpeed * dt);

        // Apply music volume
        MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
    }

    // -----------------------
    // Public SFX entry points
    // -----------------------

    public void PlayPlayerFire()
    {
        if (!_playerGunLimiter.TryConsume()) return;

        // Bullet sounds should be short + quiet-ish
        float baseVol = 0.35f;
        float vol = baseVol * RandRange(0.92f, 1.05f);
        float pitch = RandRange(-0.05f, 0.05f);

        _playerGunPool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );
    }

    public void PlayPlayerFire(BulletKind bulletKind)
    {
        if (!_playerGunLimiter.TryConsume())
            return;

        if (_playerGunPool2.TryGetValue(bulletKind, out VariantSoundPool soundPool) == false)
            return;

        // Bullet sounds should be short + quiet-ish
        float baseVol = 0.35f;
        float vol = baseVol * RandRange(0.92f, 1.05f);
        float pitch = RandRange(-0.05f, 0.05f);

        soundPool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );
    }

    public void PlayEnemyFire()
    {
        if (!_enemyGunLimiter.TryConsume()) return;

        float baseVol = 0.28f;
        float vol = baseVol * RandRange(0.90f, 1.05f);
        float pitch = RandRange(-0.07f, 0.07f);

        _enemyGunPool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );
    }

    public void PlayImpact()
    {
        if (!_impactLimiter.TryConsume()) return;

        float baseVol = 0.25f;
        float vol = baseVol * RandRange(0.90f, 1.10f);
        float pitch = RandRange(-0.08f, 0.08f);

        _impactPool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );
    }

    public void PlayExplosion(bool duckMusic = true)
    {
        float baseVol = 0.85f;
        float vol = baseVol * RandRange(0.95f, 1.05f);
        float pitch = RandRange(-0.04f, 0.04f);

        _explosionPool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );

        if (duckMusic)
        {
            // Duck music quickly, then let it recover
            DuckMusic(amount: 0.55f, holdSeconds: 0.20f, releaseSeconds: 0.35f);
        }
    }

    public void PlayPickup(PickupKind kind)
    {
        if (_pickupPool.TryGetValue(kind, out VariantSoundPool pool) == false)
            return;

        float baseVol = 0.85f;
        float vol = baseVol * RandRange(0.95f, 1.05f);
        float pitch = RandRange(-0.04f, 0.04f);

        pool.Play(
            volume: Clamp01(MasterVolume * SfxVolume * vol),
            pitch: pitch
        );
    }

    // -----------------------
    // Music
    // -----------------------

    public void PlayMusic(ContentManager content, string songAssetName, bool loop = true)
    {
        // Example asset name: "Audio/Music/level1"
        _currentSong = content.Load<Song>(songAssetName);

        MediaPlayer.IsRepeating = loop;
        MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
        MediaPlayer.Play(_currentSong);
    }

    public void StopMusic() => MediaPlayer.Stop();
    public void PauseMusic() => MediaPlayer.Pause();
    public void ResumeMusic() => MediaPlayer.Resume();

    // Duck helper: amount < 1.0 means quieter music (e.g., 0.55)
    public void DuckMusic(float amount, float holdSeconds, float releaseSeconds)
    {
        amount = Math.Clamp(amount, 0.05f, 1f);
        _musicDuckTarget = amount;

        // Use a tiny internal timer without introducing a scheduler:
        // We'll set a one-shot "return to 1" using a lightweight countdown.
        _duckReturnTimer = holdSeconds;
        _duckReleaseSeconds = Math.Max(0.01f, releaseSeconds);
    }

    private float _duckReturnTimer = 0f;
    private float _duckReleaseSeconds = 0.35f;

    // Call from Update to manage duck release
    private void HandleDuckRelease(float dt)
    {
        if (_musicDuckTarget < 1f)
        {
            _duckReturnTimer -= dt;
            if (_duckReturnTimer <= 0f)
            {
                // start releasing
                _musicDuckTarget = 1f;
                _musicDuckSpeed = 1f / _duckReleaseSeconds; // approx
                // after it reaches 1, you can restore default speed if you want
            }
        }
        else
        {
            // restore default “snappiness” once fully normal
            if (Math.Abs(_musicDuck - 1f) < 0.001f)
                _musicDuckSpeed = 6f;
        }
    }

    // Update override to include duck release handling
    public void UpdateWithDuck(GameTime gameTime)
    {
        float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

        _playerGunLimiter.Update(dt);
        _enemyGunLimiter.Update(dt);
        _impactLimiter.Update(dt);

        HandleDuckRelease(dt);

        _musicDuck = Approach(_musicDuck, _musicDuckTarget, _musicDuckSpeed * dt);
        MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
    }

    // -----------------------
    // Utilities
    // -----------------------

    private float RandRange(float min, float max)
        => (float)(min + _random.NextDouble() * (max - min));

    private static float Clamp01(float v) => Math.Clamp(v, 0f, 1f);

    private static float Approach(float current, float target, float maxDelta)
    {
        if (current < target)
            return Math.Min(current + maxDelta, target);

        if (current > target)
            return Math.Max(current - maxDelta, target);

        return current;
    }
}