import { Object3D } from "./Object3D";
import { Geometry } from "./Geometry";
import { BaseMaterial, RenderSideType } from "./materials";
import { Matrix4 } from "./math/Matrix4";
import { Ray } from "./math/Ray";
import { Sphere } from "./math/Sphere";
import { Vector3 } from "./math/Vector3";
import { Vector2 } from "./math/Vector2";
import { Raycaster, IntersectData } from "./Raycaster";

const templeSphere: Sphere = new Sphere();
const tempMatrix: Matrix4 = new Matrix4();
const tempRay: Ray = new Ray();
const tempPoint = new Vector3();
//现在基本所有3d的显示对象(sprite3d以及所有help)都继承自Mesh3D，但是以后尽量分开，包括line和point，以及材质也需要分开，TODO
export class Mesh3D extends Object3D {
    /**
     * 用于变形权重，只能获取，修改只能内部修改
     */
    private _morphTargetInfluences: number[];
    get morphTargetInfluences() {
        return this._morphTargetInfluences;
    }
    //这个暂时不知道有啥用，到时看three的
    // morphTargetDictionary
    constructor(
        public geometry: Geometry,
        public material: BaseMaterial
    ) {
        super();
        this._instanceType = "Mesh3D";
        this.updateMorphTargets();
    }
    _render(renderer) {
        if (!this.visible) return;
        renderer.batchManager.setObjectRenderer(renderer.plugins["d3"]);
        renderer.plugins["d3"].render(this)
    }

    updateMorphTargets() {
        var morphPositions = this.geometry._morphPositions;
        if (morphPositions) {
            this._morphTargetInfluences = [];
            //根据morphPositions的长度来定权重长度
            for (var i = 0; i < morphPositions.length; i++) this._morphTargetInfluences.push(0);
        }
    }

    raycast(raycaster: Raycaster, intersects: IntersectData[]) {
        if (!this.visible || !this.geometry || !this.material || this.material.wireframe) return;
        var geometry = this.geometry;
        var matrixWorld = this._worldMatrix;

        // Checking boundingSphere distance to ray

        if (!geometry.boundingSphere) geometry.computeBoundingSphere();

        templeSphere.copy(geometry.boundingSphere);
        templeSphere.applyMatrix4(matrixWorld);

        if (raycaster.ray.intersectsSphere(templeSphere) === false) return;

        //

        tempMatrix.setInverseOf(matrixWorld);
        tempRay.copy(raycaster.ray).applyMatrix4(tempMatrix);
        // Check boundingBox before continuing
        if (geometry.boundingBox !== null && tempRay.intersectsBox(geometry.boundingBox) === false) return;

        //如果不需要面检测，到此为止了
        if (!geometry.doHitFace) {
            // raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
            intersects.push({//距离简单点
                distance: raycaster.ray.origin.distanceTo(templeSphere.center) - templeSphere.radius,
                object: this
            })
            return;
        }

        var intersection: IntersectData;

        var a = new Vector3(), b = new Vector3(), c = new Vector3();
        var index = geometry._indices;
        var position = geometry._vertices;

        if (index) {
            for (var i = 0; i < index.length; i += 3) {
                var i1 = index[i], i2 = index[i + 1], i3 = index[i + 2];
                a.set(position[i1 * 3], position[i1 * 3 + 1], position[i1 * 3 + 2]);
                b.set(position[i2 * 3], position[i2 * 3 + 1], position[i2 * 3 + 2]);
                c.set(position[i3 * 3], position[i3 * 3 + 1], position[i3 * 3 + 2]);
                intersection = checkIntersection(
                    this,
                    raycaster,
                    tempRay,
                    a,
                    b,
                    c,
                    tempPoint
                );
                if (intersection) {//有一个就出
                    intersects.push(intersection);
                    break;
                }
            }
        }
        else if (position) {
            for (var i = 0; i < position.length; i += 9) {
                a.set(position[i], position[i + 1], position[i + 2]);
                b.set(position[i + 3], position[i + 4], position[i + 5]);
                c.set(position[i + 6], position[i + 7], position[i + 8]);
                intersection = checkIntersection(
                    this,
                    raycaster,
                    tempRay,
                    a,
                    b,
                    c,
                    tempPoint
                );
                if (intersection) {//有一个就出
                    intersects.push(intersection);
                    break;
                }
            }
        }
    };
    copy(source: Mesh3D, recursive: boolean = true) {
        super.copy(source, recursive);
        if (source.morphTargetInfluences) {//变形的数据
            this._morphTargetInfluences = source.morphTargetInfluences.slice();
        }
        //暂时不用
        // if ( source.morphTargetDictionary !== undefined ) {
        // 	this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
        // }
        return this
    }
    /**
     * 克隆方法
     * @param recursive 默认克隆子级
     */
    clone(recursive: boolean = true) {
        return new Mesh3D(this.geometry, this.material).copy(this, recursive);
    }
}



var intersectionPointWorld = new Vector3();
function checkIntersection(
    object: Mesh3D,
    raycaster: Raycaster,
    ray: Ray,
    pA: Vector3,
    pB: Vector3,
    pC: Vector3,
    point: Vector3
): IntersectData {
    var material = object.material
    var intersect: Vector3 | null;
    if (material.side === RenderSideType.BackSide) {
        intersect = ray.intersectTriangle(pC, pB, pA, true, point);
    } else {
        intersect = ray.intersectTriangle(pA, pB, pC, material.side !== RenderSideType.DoubleSide, point);
    }
    if (intersect === null) return null;

    intersectionPointWorld.copy(point);
    intersectionPointWorld.applyMatrix4(object._worldMatrix);
    var distance = raycaster.ray.origin.distanceTo(intersectionPointWorld);
    if (distance < raycaster.near || distance > raycaster.far) return null;
    return {
        distance: distance,
        point: intersectionPointWorld.clone(),
        object: object
    };
}
