import { assert } from "../../../../core/assert.js";
import Vector2 from '../../../../core/geom/Vector2.js';
import Vector3 from "../../../../core/geom/Vector3.js";
import Script from '../../../ecs/components/Script.js';
import { SerializationMetadata } from "../../../ecs/components/SerializationMetadata.js";
import { Tag } from "../../../ecs/components/Tag.js";
import Entity from '../../../ecs/Entity.js';
import { Transform } from "../../../ecs/transform/Transform.js";
import InputController from '../components/InputController.js';

const v3 = new Vector3();

class KeyboardCameraController {
    /**
     *
     * @constructor
     * @param {{component:TopDownCameraController, entity: number}} cameraController
     * @param {EntityComponentDataset} ecd
     */
    constructor(cameraController, ecd) {
        const controller = cameraController.component;

        assert.notEqual(controller, undefined, 'controller is undefined');

        const cameraPanSpeed = new Vector2(0, 0);

        const controls = {
            panUp: false,
            panDown: false,
            panLeft: false,
            panRight: false
        };

        function clearControls() {
            controls.panDown = false;
            controls.panUp = false;
            controls.panLeft = false;
            controls.panRight = false;
        }

        const keyboardPanSpeed = 10;

        const inputController = new InputController();

        function registerToggle(keys, object, propertyName) {
            keys.forEach((keyName) => {

                inputController.bind(
                    "keyboard/keys/" + keyName + "/down",
                    () => {
                        object[propertyName] = true;

                        //send interaction event
                        ecd.sendEvent(cameraController.entity, 'user-input');
                    }
                );
                inputController.bind(
                    "keyboard/keys/" + keyName + "/up",
                    () => object[propertyName] = false
                );
            });
        }

        registerToggle(["down_arrow", "s"], controls, "panDown");
        registerToggle(["up_arrow", "w"], controls, "panUp");
        registerToggle(["left_arrow", "a"], controls, "panLeft");
        registerToggle(["right_arrow", "d"], controls, "panRight");

        inputController.on.unlinked.add(clearControls);

        const script = new Script(function (timeDelta) {
            cameraPanSpeed.set(0, 0);

            if (controls.panDown) {
                cameraPanSpeed.y += 1;
            }
            if (controls.panUp) {
                cameraPanSpeed.y -= 1;
            }
            if (controls.panLeft) {
                cameraPanSpeed.x -= 1;
            }
            if (controls.panRight) {
                cameraPanSpeed.x += 1;
            }

            if (cameraPanSpeed.isZero()) {
                // not panning
                return;
            }

            const displacement = cameraPanSpeed.clone().multiplyScalar(keyboardPanSpeed * timeDelta);

            const camera_transform = ecd.getComponent(cameraController.entity, Transform);

            v3.set(-displacement.x, 0, -displacement.y);
            v3.applyQuaternion(camera_transform.rotation);


            controller.target.add(v3);
        });

        const builder = new Entity();

        this.builder = builder
            .add(inputController)
            .add(SerializationMetadata.Transient)
            .add(Tag.fromJSON(['Keyboard Camera Controller']))
            .add(script);
    }

    /**
     * @param {EntityComponentDataset} em
     */
    build(em) {
        return this.builder.build(em);
    }
}

export default KeyboardCameraController;
