import { clamp } from "../../../core/math/clamp.js";
import Entity from "../../ecs/Entity.js";
import { decodeMouseEventButtons } from "../../input/devices/mouse/decodeMouseEventButtons.js";
import InputController from "../../input/ecs/components/InputController.js";
import { Camera } from "../ecs/camera/Camera.js";
import TopDownCameraController, { rotate_from_view } from "../ecs/camera/topdown/TopDownCameraController.js";

/**
 *
 * @param {number} camera_entity
 * @param {EntityComponentDataset} ecd
 * @param {HTMLElement} dom_element
 * @param {number} [sensitivity]
 * @return {Entity}
 */
export function makeOrbitalCameraController({
                                                camera_entity,
                                                ecd,
                                                dom_element,
                                                sensitivity = 1
                                            }) {
    /**
     *
     * @returns {TopDownCameraController}
     */
    function getCameraController() {
        return ecd.getComponent(camera_entity, TopDownCameraController)
    }

    function getCamera() {
        return ecd.getComponent(camera_entity, Camera)
    }

    /**
     *
     * @param {Vector2} delta
     */
    function orbit(delta) {

        const cameraController = getCameraController();

        const scale = sensitivity * 2 * Math.PI / dom_element.clientHeight;

        rotate_from_view(delta.x * scale, delta.y * scale, cameraController, cameraController);
    }

    /**
     *
     * @param {Vector2} delta
     */
    function pan(delta) {

        const d = delta.clone();

        const cameraController = getCameraController();
        const camera = getCamera();

        TopDownCameraController.pan(d, camera.object, dom_element, cameraController.distance, camera.object.fov, cameraController.target);

    }

    function zoom(delta) {
        const cameraController = getCameraController();

        const new_distance = cameraController.distance + delta;
        cameraController.distance = clamp(new_distance, cameraController.distanceMin, cameraController.distanceMax);
    }

    const inputController = new InputController([
        {
            path: 'pointer/on/tap',
            listener(position, event) {
                // event.preventDefault();
            }
        },
        {
            path: 'pointer/on/down',
            listener(position, event) {
                // event.preventDefault();
            }
        },
        {
            path: 'pointer/on/drag',
            listener: function (position, origin, lastDragPosition, event) {
                const delta = lastDragPosition.clone().sub(position);

                const buttons = decodeMouseEventButtons(event.buttons);

                if (buttons[0]) {
                    pan(delta);
                } else {
                    orbit(delta);
                }

                event.preventDefault();
            }
        },
        {
            path: 'pointer/on/wheel',
            listener(delta, event) {
                zoom(delta.y);
            }
        }
    ]);

    const eb = new Entity();
    eb.add(inputController);

    return eb;
}
