import { Vector3 } from "./math/Vector3";
import { VertexArrayObject, GLBuffer, GLShader } from "../glCore";
import { HashObject } from "../2d/HashObject";
import { Vector2 } from "./math/Vector2";
import { BatchBuffer } from "../2d/renderers/webgl/BatchBuffer";
import { Box3 } from "./math/Box3";
import { Sphere } from "./math/Sphere";



/**
 * 考虑需要记录哪些几何数据
 * 暂时都在构造中执行一次数据的赋值，如果以后涉及需要动态修改数据的，加标记修改，插件里也需要重新upload数据
 */
export class Geometry extends HashObject {
    /**
     * 顶点坐标3，颜色3，uv2，法线3
     */
    _vertByteSize: number = (3 + 3 + 2 + 3) * 4;

    _vertices: Float32Array | number[];
    _indices: Uint16Array | number[];
    _colors: Float32Array | number[];
    _uvs: Float32Array | number[];
    _normals: Float32Array | number[];

    boundingBox: Box3 = null;

    boundingSphere: Sphere = null;
    /**
     * 是否按面检测
     */
    doHitFace: boolean = false;
    /**
     * 为了不同渲染器上下文对应自己的vao，不管program吧，可能不同着色器程序，带的attr可能不一样，
     * 在3d的插件上处理
     * 建vao，添加attr属性
     * 激活绑定vao
     * 绑定buffer，
     * 上传buffer数据
     * 绘制
     * 
     */
    // _glVertexArrayObjects: { [key: number]: VertexArrayObject }
    _glVaoBuffer: { [key: number]: VaoBufferInt }

    /**
     * 记录顶点数据用，包括坐标，颜色，uv，法线
     */
    _attrBuffer: BatchBuffer;

    /**
     * 顶点变形数据数组
     */

    /**
     * 法线顶点数据数组
     * 
     */

    /**
     * 
     * @param vertices 
     * @param indices 
     * @param normals 
     * @param colors 
     * @param uvs 
     */
    constructor(
        vertices: Float32Array | number[],
        indices?: Uint16Array | number[],
        normals?: Float32Array | number[],
        colors?: Float32Array | number[],
        uvs?: Float32Array | number[]
    ) {
        super();
        this._instanceType = "Geometry";
        this._glVaoBuffer = {};

        this._vertices = vertices;
        this._normals = normals || new Float32Array(vertices.length);
        this._colors = colors || new Float32Array(vertices.length).map(() => { return 1 });//不传就全是白色
        this._uvs = uvs || new Float32Array(vertices.length / 3 * 2);
        //索引直接用，可能没有
        this._indices = indices ? new Uint16Array(indices) : null;
        //顶点长度先记录
        this._attrBuffer = new BatchBuffer(vertices.length / 3 * this._vertByteSize);

    }
    computeBoundingBox() {

        if (!this.boundingBox) this.boundingBox = new Box3();

        var position = this._vertices;

        if (position) {
            this.boundingBox.setFromArray(position);
        } else {
            this.boundingBox.makeEmpty();
        }

        if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) console.error("顶点数据有误")
    };

    computeBoundingSphere() {

        var box = new Box3();
        var vector = new Vector3();

        if (!this.boundingSphere) this.boundingSphere = new Sphere();

        var position = this._vertices;

        if (position) {
            var center = this.boundingSphere.center;
            box.setFromArray(position);
            box.getCenter(center);
            // hoping to find a boundingSphere with a radius smaller than the
            // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
            var maxRadiusSq = 0;
            for (var i = 0, il = position.length; i < il; i += 3) {
                vector.x = position[i];
                vector.y = position[i + 1];
                vector.z = position[i + 2];
                maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector));
            }
            this.boundingSphere.radius = Math.sqrt(maxRadiusSq);
            if (isNaN(this.boundingSphere.radius)) console.error("顶点数据有误")
        }
    };


    destroy() {

    }
}

/**
 * 根据webglRendererId存一个，vao还需要根据着色器程序缓存
 */
interface VaoBufferInt {
    /**
     * 索引
     */
    indexBuffer?: GLBuffer,
    /**
     * 顶点相关属性
     */
    attrBuffer: GLBuffer,
    /**
     * 需要根据着色器程序id作为指向，
     * 灯光重置过着色器，基本要重来一次，上面的buffer可以留着，重新addAttr到新的vao
     */
    vaos: { [key: string]: VertexArrayObject }
}


var vertices = new Float32Array([
    2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, 2.0, // v0-v1-v2-v3 front
    2.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0, -2.0, -2.0, 2.0, 2.0, -2.0, // v0-v3-v4-v5 right
    2.0, 2.0, 2.0, 2.0, 2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, 2.0, // v0-v5-v6-v1 up
    -2.0, 2.0, 2.0, -2.0, 2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, // v1-v6-v7-v2 left
    -2.0, -2.0, -2.0, 2.0, -2.0, -2.0, 2.0, -2.0, 2.0, -2.0, -2.0, 2.0, // v7-v4-v3-v2 down
    2.0, -2.0, -2.0, -2.0, -2.0, -2.0, -2.0, 2.0, -2.0, 2.0, 2.0, -2.0  // v4-v7-v6-v5 back
]);

var colors = new Float32Array([    // Colors
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v1-v2-v3 front
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v3-v4-v5 right
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v0-v5-v6-v1 up
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v1-v6-v7-v2 left
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,     // v7-v4-v3-v2 down
    1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0　    // v4-v7-v6-v5 back
]);
colors = colors.map(() => {
    return 1
})

var normals = new Float32Array([    // Normal
    0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
    1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
    0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
    -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
    0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,  // v7-v4-v3-v2 down
    0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0   // v4-v7-v6-v5 back
]);

var uvs = new Float32Array([
    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0,
    1.0, 0.0,
]);

var indices = new Uint16Array([       // Indices of the vertices
    0, 1, 2, 0, 2, 3,    // front
    4, 5, 6, 4, 6, 7,    // right
    8, 9, 10, 8, 10, 11,    // up
    12, 13, 14, 12, 14, 15,    // left
    16, 17, 18, 16, 18, 19,    // down
    20, 21, 22, 20, 22, 23     // back
]);


function createNineTextures(imageUrl: string): Promise<FYGE.Texture[]> {
    return new Promise((resolve, reject) => {
        let image = new Image();
        image.onload = function () {
            var obj = {}
            //名字。
            var name = "lalala";
            var w = image.width / 3;
            var h = image.height / 3;
            //生成9张图的数据
            for (var i = 0; i < 9; i++)
                obj[name + i] = {
                    "x": i % 3 * w,
                    "y": ~~(i / 3) * h,
                    w, h, sw: w, sh: h, ox: 0, oy: 0, ro: false
                };
            FYGE.createTextureSheet(new FYGE.BaseTexture(image), obj);
            //取TextureCache里的
            var arr = [];
            for (var i = 0; i < 9; i++)arr.push(FYGE.TextureCache[name + i])
            resolve(arr)
        }
        image.onerror = function () {
            reject()
        }
        image.src = imageUrl
    })
}
