package de.blight.game.control;

import com.jme3.input.InputManager;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.math.*;
import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial;

/**
 * Third-Person-Kamera:
 * - Mausbewegung       → Kamera um den Charakter drehen (immer, kein Klick nötig)
 * - Y-Achse invertiert → Maus hoch = Kamera runter (oldschool)
 * - Mausrad            → Zoom (Abstand)
 */
public class ThirdPersonCamera {

    private static final float MOUSE_SENSITIVITY  = 1.8f;
    private static final float MIN_DISTANCE       = 3f;
    private static final float MAX_DISTANCE       = 20f;
    private static final float MIN_VERTICAL_ANGLE = -0.3f;
    private static final float MAX_VERTICAL_ANGLE = FastMath.HALF_PI - 0.1f;
    private static final float TARGET_HEIGHT      = 1.6f;

    private final Camera cam;
    private final InputManager inputManager;

    private Spatial target;

    private float yaw      = 0f;
    private float pitch    = 0.4f;
    private float distance = 10f;
    private boolean paused = false;

    public ThirdPersonCamera(Camera cam, InputManager inputManager) {
        this.cam = cam;
        this.inputManager = inputManager;
        registerMappings();
    }

    public void setTarget(Spatial target) {
        this.target = target;
    }

    public void setPaused(boolean paused) { this.paused = paused; }

    // -----------------------------------------------------------------------

    private void registerMappings() {
        inputManager.addMapping("ZoomIn",    new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
        inputManager.addMapping("ZoomOut",   new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
        inputManager.addMapping("MouseX",    new MouseAxisTrigger(MouseInput.AXIS_X, false));
        inputManager.addMapping("MouseXNeg", new MouseAxisTrigger(MouseInput.AXIS_X, true));
        inputManager.addMapping("MouseY",    new MouseAxisTrigger(MouseInput.AXIS_Y, false));
        inputManager.addMapping("MouseYNeg", new MouseAxisTrigger(MouseInput.AXIS_Y, true));

        AnalogListener analogListener = (name, value, tpf) -> {
            if (paused) return;
            switch (name) {
                // Horizontale Rotation
                case "MouseX"    -> yaw  -= value * MOUSE_SENSITIVITY;
                case "MouseXNeg" -> yaw  += value * MOUSE_SENSITIVITY;
                // Vertikale Rotation — Y invertiert: Maus hoch → Kamera runter
                case "MouseY"    -> pitch = FastMath.clamp(pitch - value * MOUSE_SENSITIVITY, MIN_VERTICAL_ANGLE, MAX_VERTICAL_ANGLE);
                case "MouseYNeg" -> pitch = FastMath.clamp(pitch + value * MOUSE_SENSITIVITY, MIN_VERTICAL_ANGLE, MAX_VERTICAL_ANGLE);
                // Zoom
                case "ZoomIn"    -> distance = FastMath.clamp(distance - value * 20f, MIN_DISTANCE, MAX_DISTANCE);
                case "ZoomOut"   -> distance = FastMath.clamp(distance + value * 20f, MIN_DISTANCE, MAX_DISTANCE);
            }
        };
        inputManager.addListener(analogListener,
            "MouseX", "MouseXNeg", "MouseY", "MouseYNeg", "ZoomIn", "ZoomOut");
    }

    public void update(float tpf) {
        if (target == null) return;

        Vector3f pivot = target.getWorldTranslation().add(0, TARGET_HEIGHT, 0);

        // Sphärische Koordinaten → kartesisch
        float x = distance * FastMath.cos(pitch) * FastMath.sin(yaw);
        float y = distance * FastMath.sin(pitch);
        float z = distance * FastMath.cos(pitch) * FastMath.cos(yaw);

        Vector3f camPos = pivot.add(x, y, z);
        cam.setLocation(camPos);
        cam.lookAt(pivot, Vector3f.UNIT_Y);
    }

    /** Aktueller Yaw-Winkel (für CharacterControl nutzbar). */
    public float getYaw() { return yaw; }
}
