import { Object3D } from "./Object3D";
import { Camera } from "./cameras/Camera";
import { PerspectiveCamera } from "./cameras/PerspectiveCamera";
import { WebglRenderer } from "../2d/renderers/WebglRenderer";
import { D3Renderer } from "./D3Renderer";
import { Light } from "./lights/Light";
import { PointLight } from "./lights/PointLight";
import { DirectionalLight } from "./lights/DirectionalLight";
import { Vector3 } from "./math/Vector3";
import { Point } from "../2d/math";
import { Vector2 } from "./math/Vector2";
import { MouseEvent } from "../2d/events";
import { Raycaster } from "./Raycaster";


/**
 * 作为3D的顶级容器，不能被object3D添加，自身不能添加其他2D元素
 * 带透明度的融合有问题，尽量自行调整渲染顺序
 */
export class Scene3D extends Object3D {
    private _localID: number = 0;
    private _viewX: number = 0;
    get viewX() {
        return this._viewX;
    }
    set viewX(value: number) {
        value = value || 0;
        if (this._viewX === value) return;
        this._viewX = value;
        this._localID = -1;
    }
    private _viewY: number = 0;
    get viewY() {
        return this._viewY;
    }
    set viewY(value: number) {
        value = value || 0;
        if (this._viewY === value) return;
        this._viewY = value;
        this._localID = -1;
    }

    private _viewWidth: number = 300;
    get viewWidth() {
        return this._viewWidth;
    }
    set viewWidth(value: number) {
        value = value || 0;
        if (this._viewWidth === value) return;
        this._viewWidth = value;
        this._localID = -1;
    }
    private _viewHeight: number = 300;
    get viewHeight() {
        return this._viewHeight;
    }
    set viewHeight(value: number) {
        value = value || 0;
        if (this._viewHeight === value) return;
        this._viewHeight = value;
        this._localID = -1;
    }

    /**
     * 父级是2d元素，用于修改视窗位置
     */
    parent: any

    visible: boolean = true
    /**
     * 相机
     */
    camera: Camera;

    private raycaster:Raycaster
    constructor() {
        super()
        this._instanceType = "Scene3D";
        //@ts-ignore为了添加进容器时候的操作，做个兼容
        this.transform = { _parentId: 0 }
        this.camera = new PerspectiveCamera();

        // this.raycaster = new Raycaster();
    }
    //只处理自己的xy坐标
    updateTransform() {
        if (!this.visible) return
        //子级统统自己的更新方法
        this.updateWorldMatrix();
    }

    renderWebGL(renderer: WebglRenderer) {
        if (!this.visible) return

        //切换渲染插件
        var plugin: D3Renderer = renderer.plugins["d3"];
        //传入camera数据，着色器各自传
        this.camera.updateWorldMatrix();
        plugin.camera = this.camera;
        //处理所有灯，只找同一级的？还是递归找灯
        plugin.lightsConfig = this.getLightConfig();
        //查找有哪些材质，确定需要初始化哪些着色器

        //设置插件，会调用start，如果是两个场景，会有问题，因为是同一个插件不会flush上一个，到时注意修改
        renderer.batchManager.setObjectRenderer(plugin);


        //自己的位置
        if (this._localID !== this.parent.transform._worldID) {
            var pt = this.parent.transform.worldMatrix;
            var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
            var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
            //计算实际的viewWidth和viewHeight，简单点直接是父级的缩放，还是要全局的缩放，如果只在舞台
            var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
            var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
            //每个场景
            renderer.gl.viewport(
                x,
                renderer.height - y - this.viewHeight * scaleY,
                this.viewWidth * scaleX,
                this.viewHeight * scaleY
            )
        }
        //处理子级东西
        this.render(renderer)
    }

    getLightConfig(
        con: Object3D = this,
        arr: LightsConfig = { pointLights: [], directionalLights: [], ambientLightColor: [0, 0, 0] }
    ) {
        var viewMatrix = this.camera.worldMatrixInverse;
        for (var i = 0; i < con.children.length; i++) {
            var c = con.children[i] as Light;
            if (!(c instanceof Light)) continue;
            var color: number[] = c.colorVec3.clone().multiplyScalar(c.intensity).toArray();
            if (c.instanceType == "AmbientLight") {
                arr.ambientLightColor[0] += color[0];
                arr.ambientLightColor[1] += color[1];
                arr.ambientLightColor[2] += color[2];
            }
            else if (c.instanceType == "PointLight") {
                var position: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
                position.applyMatrix4(viewMatrix);//这步是否需要，待测试
                arr.pointLights.push({
                    color: color,
                    position: position.toArray(),
                    distance: c["distance"],
                    decay: c["distance"] === 0 ? 0.0 : c["decay"],
                })
            }
            else if (c.instanceType == "DirectionalLight") {
                var direction: Vector3 = new Vector3().setFromMatrixPosition(c._worldMatrix);
                direction.sub(new Vector3().setFromMatrixPosition(c["target"]._worldMatrix));
                direction.transformDirection(viewMatrix);
                arr.directionalLights.push({
                    color: color,
                    direction: direction.normalize().toArray()
                })
            }
            if (c.children && c.children.length) this.getLightConfig(c, arr);
        }
        return arr
    }
    /**
     * 点击事件，只算场景的先，待mesh等写完所有2d包围盒再说，将几何转成2d的点后，根据索引的所有三角面计算是否选中
     * @param globalPoint 
     * @param isMouseEvent 
     */
    hitTestPoint(globalPoint: Point, isMouseEvent: boolean = false) {
        if (!this.parent || !this.mouseEnable) return null;
        //转成全局
        var pt = this.parent.transform.worldMatrix;
        var x = (this.viewX * pt.a) + (this.viewY * pt.c) + pt.tx;
        var y = (this.viewX * pt.b) + (this.viewY * pt.d) + pt.ty;
        //计算实际的viewWidth和viewHeight，简单点直接是父级的缩放，还是要全局的缩放，如果只在舞台
        var scaleX = Math.sqrt((pt.a * pt.a) + (pt.b * pt.b));
        var scaleY = Math.sqrt((pt.c * pt.c) + (pt.d * pt.d));
        var w = this.viewWidth * scaleX;
        var h = this.viewHeight * scaleY;

        if (globalPoint.x >= x && globalPoint.x <= (x + w) && globalPoint.y >= y && globalPoint.y <= (y + h)) {
        } else {
            return null;
        }
        //检查场景中的
        if (this.mouseChildren) {

        }

        return this;
    }

    /**
     * 为了兼容stage里鼠标事件需要计算localX和localY
     * @param vector 
     */
    globalToLocal(vector: Vector3) {
        return vector
    }

    //相机控件
    setOrbitControl() {
        // sphericalDelta.theta *= ( 1 - scope.dampingFactor );
        // sphericalDelta.phi *= ( 1 - scope.dampingFactor );

        // panOffset.multiplyScalar( 1 - scope.dampingFactor );
        //相机目标点
        var center = new Vector3();
        // this.userZoom = true;
        // this.userZoomSpeed = 1.0;

        //旋转参数，暂时只有旋转;
        var userRotate = true;
        var userRotateSpeed = 1.0;

        // this.userPan = true;
        // this.userPanSpeed = 2.0;

        var autoRotate = false;
        var autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60

        //最小旋转角
        var minPolarAngle = 0;
        //最大旋转角
        var maxPolarAngle = Math.PI;

        var minDistance = 0;
        var maxDistance = Infinity;

        var EPS = 0.000001;
        var PIXELS_PER_ROUND = 1800;

        var rotateStart = new Vector2();
        var rotateEnd = new Vector2();
        var rotateDelta = new Vector2();

        var phiDelta = 0;
        var thetaDelta = 0;
        var scale = 1;

        function getAutoRotationAngle() {
            return 2 * Math.PI / 60 / 60 * autoRotateSpeed;
        }

        function rotateLeft(angle: number = getAutoRotationAngle()) {
            thetaDelta -= angle;
        };

        function rotateRight(angle: number = getAutoRotationAngle()) {
            thetaDelta += angle;
        };

        function rotateUp(angle: number = getAutoRotationAngle()) {
            phiDelta -= angle;
        };

        function rotateDown(angle: number = getAutoRotationAngle()) {
            phiDelta += angle;
        };

        let update = () => {

            var position = this.camera.position;
            var offset = position.clone().sub(center);
            var theta = Math.atan2(offset.x, offset.z);
            var phi = Math.atan2(Math.sqrt(offset.x * offset.x + offset.z * offset.z), offset.y);

            if (autoRotate) rotateLeft();

            theta += thetaDelta;
            phi += phiDelta;

            phi = Math.max(minPolarAngle, Math.min(maxPolarAngle, phi));

            phi = Math.max(EPS, Math.min(Math.PI - EPS, phi));

            var radius = offset.length() * scale;

            // restrict radius to be between desired limits
            radius = Math.max(minDistance, Math.min(maxDistance, radius));

            offset.x = radius * Math.sin(phi) * Math.sin(theta);
            offset.y = radius * Math.cos(phi);
            offset.z = radius * Math.sin(phi) * Math.cos(theta);

            //相机位置
            position.copy(center).add(offset);

            //相机目标点
            this.camera.lookAt(center.x, center.y, center.z);

            //恢复
            thetaDelta = 0;
            phiDelta = 0;
            scale = 1;
            // if (lastPosition.distanceTo(this.object.position) > 0) {
            //     this.dispatchEvent(changeEvent);
            //     lastPosition.copy(this.object.position);
            // }
        };

        //事件，暂时只有旋转，其他判断先不要了
        this.addEventListener(MouseEvent.MOUSE_DOWN, (e: MouseEvent) => {
            e.stopPropagation();
            rotateStart.set(e.clientX, e.clientY);

            this.addEventListener(MouseEvent.MOUSE_MOVE, move, this);
            this.addEventListener(MouseEvent.MOUSE_UP, up, this);
            this.addEventListener(MouseEvent.MOUSE_OUT, up, this);

            function move(e: MouseEvent) {
                rotateEnd.set(e.clientX, e.clientY);
                rotateDelta.subVectors(rotateEnd, rotateStart);
                rotateLeft(2 * Math.PI * rotateDelta.x / PIXELS_PER_ROUND * userRotateSpeed);
                rotateUp(2 * Math.PI * rotateDelta.y / PIXELS_PER_ROUND * userRotateSpeed);
                rotateStart.copy(rotateEnd);
                //更新
                update();
            }
            function up(e: MouseEvent) {
                this.removeEventListener(MouseEvent.MOUSE_MOVE, move, this);
                this.removeEventListener(MouseEvent.MOUSE_UP, up, this);
                this.removeEventListener(MouseEvent.MOUSE_OUT, up, this);
            }
        }, this);

        //加个自动旋转的
        this.addEventListener(MouseEvent.ENTER_FRAME, () => {
            if (autoRotate) update()
        }, this)
    }
}



export interface LightsConfig {
    pointLights: PointLightConfig[],
    directionalLights: DirectionalLightConfig[],
    ambientLightColor: number[],
}

interface PointLightConfig {
    color: number[],//光源颜色
    position: number[],//点光源位置
    distance: number,//最大光源距离
    decay: number,//衰减系数，默认1，最佳2
}

interface DirectionalLightConfig {
    direction: number[],
    color: number[],
}