import { Component, EventKeyboard, EventMouse, Input, input, KeyCode, Vec3, _decorator } from 'cc';
const { ccclass, property } = _decorator;

export const INPUT = {
    LEFT: 0,
    RIGHT: 0,
    UP: 0,
    DOWN: 0,
    FOWARD: 0,
    BACKWARD: 0,

    ZOOM: 0,

    ROTATE: 0,
    ROTATE_PARAMS: { x: 0, y: 0 },
};

@ccclass('CameraCtrl')
export class CameraCtrl extends Component {
    /* -- PROPERTIES -- */

    @property
    public speed = 100; // 平移速度

    @property
    public rotateSpeed = 10; // 旋转速度

    @property
    public zoomSpeed = 0.05; // 镜头缩放速度

    private velocity = new Vec3();
    private rotateVelocity = new Vec3();

    /* -- LIFE CYCLE -- */

    public onLoad() {
        this.addListener();
    }

    public start() {}

    public update(dt: number) {
        this.cameraMove(dt);
    }

    public onDestroy() {
        this.removeListener();
    }

    /* -- METHODS -- */
    public getVelocaity() {
        return this.velocity;
    }

    public addListener() {
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this);

        input.on(Input.EventType.MOUSE_MOVE, this.onMouseMove, this);
        input.on(Input.EventType.MOUSE_DOWN, this.onMouseDown, this);
        input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
        input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
    }

    public removeListener() {
        input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.off(Input.EventType.KEY_UP, this.onKeyUp, this);

        input.off(Input.EventType.MOUSE_MOVE, this.onMouseMove, this);
        input.off(Input.EventType.MOUSE_DOWN, this.onMouseDown, this);
        input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this);
        input.off(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
    }

    private onKeyDown(event: EventKeyboard) {
        switch (event.keyCode) {
            case KeyCode.KEY_A:
                INPUT.LEFT = 1;
                break;
            case KeyCode.KEY_D:
                INPUT.RIGHT = 1;
                break;
            case KeyCode.KEY_W:
                INPUT.FOWARD = 1;
                break;
            case KeyCode.KEY_S:
                INPUT.BACKWARD = 1;
                break;
            case KeyCode.SPACE:
            case KeyCode.KEY_E:
                INPUT.UP = 1;
                break;
            case KeyCode.CTRL_LEFT:
            case KeyCode.KEY_Q:
                INPUT.DOWN = 1;
                break;
        }
    }

    private onKeyUp(event: EventKeyboard) {
        switch (event.keyCode) {
            case KeyCode.KEY_A:
                INPUT.LEFT = 0;
                break;
            case KeyCode.KEY_D:
                INPUT.RIGHT = 0;
                break;
            case KeyCode.KEY_W:
                INPUT.FOWARD = 0;
                break;
            case KeyCode.KEY_S:
                INPUT.BACKWARD = 0;
                break;
            case KeyCode.SPACE:
            case KeyCode.KEY_E:
                INPUT.UP = 0;
                break;
            case KeyCode.CTRL_LEFT:
            case KeyCode.KEY_Q:
                INPUT.DOWN = 0;
                break;
        }
    }

    private onMouseMove(event: EventMouse) {
        if (INPUT.ROTATE === 1) {
            INPUT.ROTATE_PARAMS.x = event.movementX;
            INPUT.ROTATE_PARAMS.y = event.movementY;
        }
    }

    private onMouseDown(event: EventMouse) {
        switch (event.getButton()) {
            case EventMouse.BUTTON_RIGHT:
                INPUT.ROTATE = 1;
                break;
        }
    }

    private onMouseUp(event: EventMouse) {
        switch (event.getButton()) {
            case EventMouse.BUTTON_RIGHT:
                INPUT.ROTATE = 0;
                break;
        }
    }

    private onMouseWheel(event: EventMouse) {
        INPUT.ZOOM = event.getScrollY();
    }

    private cameraMove(dt: number) {
        this.velocity.set(0, 0, 0);

        if (INPUT.LEFT === 1) {
            this.velocity.subtract(this.node.right);
        }

        if (INPUT.RIGHT === 1) {
            this.velocity.add(this.node.right);
        }

        if (INPUT.FOWARD === 1) {
            this.velocity.add(this.node.forward);
        }

        if (INPUT.BACKWARD === 1) {
            this.velocity.subtract(this.node.forward);
        }

        if (INPUT.UP === 1) {
            this.velocity.add(Vec3.UP);
        }

        if (INPUT.DOWN === 1) {
            this.velocity.subtract(Vec3.UP);
        }

        if (INPUT.ZOOM !== 0) {
            Vec3.multiplyScalar(this.velocity, this.node.forward, INPUT.ZOOM * this.zoomSpeed);
            INPUT.ZOOM = 0;
        }

        const newPos = this.node.worldPosition.add(this.velocity.multiplyScalar(this.speed * dt));
        this.node.setWorldPosition(newPos);

        if (INPUT.ROTATE === 1) {
            const eulerAngles = this.node.eulerAngles;
            this.rotateVelocity.set(-INPUT.ROTATE_PARAMS.y, -INPUT.ROTATE_PARAMS.x, 0);
            this.node.setRotationFromEuler(eulerAngles.add(this.rotateVelocity.multiplyScalar(this.rotateSpeed * dt)));

            INPUT.ROTATE_PARAMS.x = 0;
            INPUT.ROTATE_PARAMS.y = 0;
        }
    }
}


