package net.minecraft.client.resources.sounds;

import net.minecraft.sounds.SoundSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.Level;
import net.minecraft.util.Mth;
import net.minecraft.world.level.LightLayer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.biome.AmbientAdditionsSettings;
import net.minecraft.world.level.biome.AmbientMoodSettings;
import java.util.Optional;
import net.minecraft.world.level.biome.Biome;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.util.Random;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.client.sounds.SoundManager;
import net.minecraft.client.player.LocalPlayer;

public class BiomeAmbientSoundsHandler implements AmbientSoundHandler {
    private final LocalPlayer player;
    private final SoundManager soundManager;
    private final BiomeManager biomeManager;
    private final Random random;
    private Object2ObjectArrayMap<Biome, LoopSoundInstance> loopSounds;
    private Optional<AmbientMoodSettings> moodSettings;
    private Optional<AmbientAdditionsSettings> additionsSettings;
    private float moodiness;
    private Biome previousBiome;
    
    public BiomeAmbientSoundsHandler(final LocalPlayer ebf, final SoundManager epn, final BiomeManager brg) {
        this.loopSounds = (Object2ObjectArrayMap<Biome, LoopSoundInstance>)new Object2ObjectArrayMap();
        this.moodSettings = Optional.<AmbientMoodSettings>empty();
        this.additionsSettings = Optional.<AmbientAdditionsSettings>empty();
        this.random = ebf.level.getRandom();
        this.player = ebf;
        this.soundManager = epn;
        this.biomeManager = brg;
    }
    
    public float getMoodiness() {
        return this.moodiness;
    }
    
    @Override
    public void tick() {
        this.loopSounds.values().removeIf(AbstractTickableSoundInstance::isStopped);
        final Biome bre2 = this.biomeManager.getNoiseBiomeAtPosition(this.player.getX(), this.player.getY(), this.player.getZ());
        if (bre2 != this.previousBiome) {
            this.previousBiome = bre2;
            this.moodSettings = bre2.getAmbientMood();
            this.additionsSettings = bre2.getAmbientAdditions();
            this.loopSounds.values().forEach(LoopSoundInstance::fadeOut);
            final LoopSoundInstance loopSoundInstance;
            bre2.getAmbientLoop().ifPresent(ack -> loopSoundInstance = (LoopSoundInstance)this.loopSounds.compute(bre2, (bre, a) -> {
                if (a == null) {
                    a = new LoopSoundInstance(ack);
                    this.soundManager.play(a);
                }
                a.fadeIn();
                return a;
            }));
        }
        this.additionsSettings.ifPresent(bqv -> {
            if (this.random.nextDouble() < bqv.getTickChance()) {
                this.soundManager.play(SimpleSoundInstance.forAmbientAddition(bqv.getSoundEvent()));
            }
            return;
        });
        final Level bqb3;
        final int integer4;
        final BlockPos fu5;
        final int integer5;
        double double7;
        double double8;
        double double9;
        double double10;
        double double11;
        double double12;
        double double13;
        double double14;
        SimpleSoundInstance eoi23;
        this.moodSettings.ifPresent(bqw -> {
            bqb3 = this.player.level;
            integer4 = bqw.getBlockSearchExtent() * 2 + 1;
            fu5 = new BlockPos(this.player.getX() + this.random.nextInt(integer4) - bqw.getBlockSearchExtent(), this.player.getEyeY() + this.random.nextInt(integer4) - bqw.getBlockSearchExtent(), this.player.getZ() + this.random.nextInt(integer4) - bqw.getBlockSearchExtent());
            integer5 = bqb3.getBrightness(LightLayer.SKY, fu5);
            if (integer5 > 0) {
                this.moodiness -= integer5 / (float)bqb3.getMaxLightLevel() * 0.001f;
            }
            else {
                this.moodiness -= (bqb3.getBrightness(LightLayer.BLOCK, fu5) - 1) / (float)bqw.getTickDelay();
            }
            if (this.moodiness >= 1.0f) {
                double7 = fu5.getX() + 0.5;
                double8 = fu5.getY() + 0.5;
                double9 = fu5.getZ() + 0.5;
                double10 = double7 - this.player.getX();
                double11 = double8 - this.player.getEyeY();
                double12 = double9 - this.player.getZ();
                double13 = Mth.sqrt(double10 * double10 + double11 * double11 + double12 * double12);
                double14 = double13 + bqw.getSoundPositionOffset();
                eoi23 = SimpleSoundInstance.forAmbientMood(bqw.getSoundEvent(), this.player.getX() + double10 / double13 * double14, this.player.getEyeY() + double11 / double13 * double14, this.player.getZ() + double12 / double13 * double14);
                this.soundManager.play(eoi23);
                this.moodiness = 0.0f;
            }
            else {
                this.moodiness = Math.max(this.moodiness, 0.0f);
            }
        });
    }
    
    public static class LoopSoundInstance extends AbstractTickableSoundInstance {
        private int fadeDirection;
        private int fade;
        
        public LoopSoundInstance(final SoundEvent ack) {
            super(ack, SoundSource.AMBIENT);
            this.looping = true;
            this.delay = 0;
            this.volume = 1.0f;
            this.relative = true;
        }
        
        @Override
        public void tick() {
            if (this.fade < 0) {
                this.stop();
            }
            this.fade += this.fadeDirection;
            this.volume = Mth.clamp(this.fade / 40.0f, 0.0f, 1.0f);
        }
        
        public void fadeOut() {
            this.fade = Math.min(this.fade, 40);
            this.fadeDirection = -1;
        }
        
        public void fadeIn() {
            this.fade = Math.max(0, this.fade);
            this.fadeDirection = 1;
        }
    }
}
