package zenith.zov.base.rotation;

import lombok.Generated;
import net.minecraft.util.math.MathHelper;
import zenith.zov.base.rotation.mods.AIRotationMode;
import zenith.zov.base.rotation.mods.InstantRotationMode;
import zenith.zov.base.rotation.mods.InterpolationRotationMode;
import zenith.zov.base.rotation.mods.config.AiRotationConfig;
import zenith.zov.base.rotation.mods.config.InstantRotationConfig;
import zenith.zov.base.rotation.mods.config.InterpolationRotationConfig;
import zenith.zov.base.rotation.mods.config.api.RotationConfig;
import zenith.zov.base.rotation.mods.config.api.RotationModeType;
import zenith.zov.utility.game.player.rotation.Rotation;
import zenith.zov.utility.game.player.rotation.RotationDelta;
import zenith.zov.utility.interfaces.IClient;

public class AimManager implements IClient {
    private final InterpolationRotationMode interpolationMod = new InterpolationRotationMode();
    private final InstantRotationMode instantMod = new InstantRotationMode();
    private final AIRotationMode smoothMod = new AIRotationMode();
    private final RotationConfig instantSetup = new InstantRotationConfig();
    private final RotationConfig aiSetup = AiRotationConfig.builder().build();
    int index = 0;
    float[] values = new float[]{0.0123967F, 0.053719F, 0.109504F, 0.17562F, 0.21281F, 0.272727F, 0.11157F, 0.0392562F, 0.0103306F, 0.00206612F};

    public Rotation rotate(RotationConfig config, Rotation targetRotation) {
        if (config.getType() != RotationModeType.INSTANT) {
            RotationDelta deltaToTarget = zenith.getRotationManager().getCurrentRotation().rotationDeltaTo(targetRotation);
            float maxInitialDiff = 270.0F;
            float progress = MathHelper.clamp(
                1.0F - (Math.abs(deltaToTarget.getDeltaYaw()) + Math.abs(deltaToTarget.getDeltaPitch())) / maxInitialDiff, 0.0F, 1.0F
            );
            RotationDelta offsets = getOffset(deltaToTarget, progress);
            targetRotation = targetRotation.add(offsets);
        }
        Rotation var7 = switch (config.getType()) {
            case INSTANT -> this.instantMod.process(targetRotation);
            case INTERPOLATION -> this.interpolationMod
            .process((InterpolationRotationConfig)config, zenith.getRotationManager().getCurrentRotation(), targetRotation);
            case AI -> this.interpolationMod
            .process(
                ((AiRotationConfig)config).getInterpolationRotationConfig(), this.smoothMod.process((AiRotationConfig)config, targetRotation), targetRotation
            );
            default -> zenith.getRotationManager().getCurrentRotation();
        };
        if (config.getType() != RotationModeType.AI) {
        }

        return rotationManager.getCurrentRotation().equals(var7) ? var7 : var7.normalize(new Rotation(mc.player.lastYaw, mc.player.lastPitch));
    }

    public void incrementIndex() {
        this.index++;
        if (this.index >= this.values.length) {
            this.index = 0;
        }
    }

    public float getDiff(float prevTargetYawDiff, float targetYawDiff) {
        return targetYawDiff * this.values[this.index];
    }

    public static RotationDelta getOffset(RotationDelta deltaToTarget, float progress) {
        float curveStrength = 3.0F;
        float smoothness = 1.0F - (float)Math.cos((double)progress * Math.PI);
        float yawSign = Math.signum(deltaToTarget.getDeltaYaw());
        float pitchSign = Math.signum(deltaToTarget.getDeltaPitch());
        float offsetYaw = 0.0F;
        float offsetPitch = 0.0F;
        boolean verticalAiming = Math.abs(deltaToTarget.getDeltaYaw()) < 1.5F && Math.abs(deltaToTarget.getDeltaPitch()) > 10.0F;
        if (verticalAiming) {
            offsetYaw = pitchSign * curveStrength * (1.0F - progress);
            offsetPitch = 0.0F;
        } else if (pitchSign > 0.0F && yawSign >= 0.0F) {
            offsetYaw = -curveStrength * (1.0F - progress);
            offsetPitch = -curveStrength * smoothness;
        } else if (pitchSign > 0.0F && yawSign < 0.0F) {
            offsetYaw = curveStrength * (1.0F - progress);
            offsetPitch = -curveStrength * smoothness;
        } else if (pitchSign < 0.0F && yawSign >= 0.0F) {
            offsetYaw = -curveStrength * (1.0F - progress);
            offsetPitch = curveStrength * smoothness;
        } else if (pitchSign < 0.0F && yawSign < 0.0F) {
            offsetYaw = curveStrength * (1.0F - progress);
            offsetPitch = curveStrength * smoothness;
        }

        return new RotationDelta(offsetYaw, offsetPitch);
    }

    public void reset() {
        this.index = 0;
    }

    @Generated
    public RotationConfig getInstantSetup() {
        return this.instantSetup;
    }

    @Generated
    public RotationConfig getAiSetup() {
        return this.aiSetup;
    }

    @Generated
    public int getIndex() {
        return this.index;
    }
}
