package zenith.zov.client.modules.impl.render;

import com.darkmagician6.eventapi.EventTarget;
import java.util.List;
import net.minecraft.client.option.Perspective;
import net.minecraft.util.math.MathHelper;
import zenith.zov.base.events.impl.input.EventHotBarScroll;
import zenith.zov.base.events.impl.input.EventKey;
import zenith.zov.base.events.impl.input.EventMouseRotation;
import zenith.zov.base.events.impl.render.EventAspectRatio;
import zenith.zov.base.events.impl.render.EventCamera;
import zenith.zov.base.events.impl.render.EventFov;
import zenith.zov.client.modules.api.Category;
import zenith.zov.client.modules.api.Module;
import zenith.zov.client.modules.api.ModuleAnnotation;
import zenith.zov.client.modules.api.setting.impl.KeySetting;
import zenith.zov.client.modules.api.setting.impl.MultiBooleanSetting;
import zenith.zov.client.modules.api.setting.impl.NumberSetting;
import zenith.zov.utility.game.player.PlayerIntersectionUtil;
import zenith.zov.utility.game.player.rotation.Rotation;
import zenith.zov.utility.math.MathUtil;

@ModuleAnnotation(
    name = "CameraTweaks",
    description = "Camera settings",
    category = Category.MISC
)
public class CameraTweaks extends Module {
    public static final CameraTweaks INSTANCE = new CameraTweaks();
    private float fov = 110.0F;
    private float smoothFov = 30.0F;
    private float lastChangedFov = 30.0F;
    private Perspective perspective;
    private Rotation angle;
    private final MultiBooleanSetting multiSetting = MultiBooleanSetting.create("Settings", List.of("Aspect Ratio", "Camera Clip", "Camera Distance"));
    private final NumberSetting ratioSetting = new NumberSetting("Aspect Ratio", 1.0F, 0.1F, 2.0F, 0.1F, () -> this.multiSetting.isEnable(0));
    private final NumberSetting distanceSetting = new NumberSetting("Camera Distance", 3.0F, 2.0F, 5.0F, 0.5F, () -> this.multiSetting.isEnable(2));
    private final KeySetting zoomSetting = new KeySetting("Zoom");
    private final KeySetting freeLookSetting = new KeySetting("Free Look");

    private CameraTweaks() {
    }

    @EventTarget
    public void onKey(EventKey e) {
        if (e.is(this.zoomSetting.getKeyCode())) {
            this.fov = Math.min(this.lastChangedFov, (float)((Integer)mc.options.getFov().getValue() - 20));
        }

        if (e.isKeyReleased(this.zoomSetting.getKeyCode(), true)) {
            this.lastChangedFov = this.fov;
            this.fov = (float)((Integer)mc.options.getFov().getValue()).intValue();
        }

        if (e.isKeyDown(this.freeLookSetting.getKeyCode())) {
            this.perspective = mc.options.getPerspective();
        }
    }

    @EventTarget
    public void onHotBarScroll(EventHotBarScroll e) {
        if (PlayerIntersectionUtil.isKey(this.zoomSetting)) {
            this.fov = (float)(
                (int)MathHelper.clamp(
                    (double)this.fov - e.getVertical() * 10.0, 10.0, (double)((Integer)mc.options.getFov().getValue()).intValue()
                )
            );
            e.setCancelled(true);
        }
    }

    @EventTarget
    public void onFov(EventFov e) {
        if (PlayerIntersectionUtil.isKey(this.freeLookSetting)) {
            if (mc.options.getPerspective().isFirstPerson()) {
                mc.options.setPerspective(Perspective.THIRD_PERSON_BACK);
            }
        } else if (this.perspective != null) {
            mc.options.setPerspective(this.perspective);
            this.perspective = null;
        }

        if (this.zoomSetting.isVisible()) {
            e.setFov(
                (int)MathHelper.clamp(
                    (this.smoothFov = MathUtil.interpolateSmooth(1.6, this.smoothFov, this.fov)) + 1.0F,
                    10.0F,
                    (float)((Integer)mc.options.getFov().getValue()).intValue()
                )
            );
            e.cancel();
        }
    }

    @EventTarget
    public void onMouseRotation(EventMouseRotation e) {
        if (PlayerIntersectionUtil.isKey(this.freeLookSetting)) {
            this.angle = new Rotation(
                this.angle.getYaw() + e.getCursorDeltaX() * 0.15F, MathHelper.clamp(this.angle.getPitch() + e.getCursorDeltaY() * 0.15F, -90.0F, 90.0F)
            );
            e.setCancelled(true);
        } else {
            this.angle = new Rotation(mc.player.getYaw(), mc.player.getPitch());
        }
    }

    @EventTarget
    public void onCamera(EventCamera e) {
        e.setCameraClip(this.multiSetting.isEnable(1));
        if (this.multiSetting.isEnable(2)) {
            e.setDistance(this.distanceSetting.getCurrent());
        }

        e.setAngle(this.angle);
        e.cancel();
    }

    @EventTarget
    public void onAspectRatio(EventAspectRatio e) {
        if (this.multiSetting.isEnable(0)) {
            e.setRatio(this.ratioSetting.getCurrent());
            e.setCancelled(true);
        }
    }
}
