import { AmbientLight, BoxBufferGeometry, Camera, Material, Mesh, MeshPhysicalMaterial, OrthographicCamera, PointLight, Scene, Sprite, SpriteMaterial, WebGLRenderer } from 'three';

export class MaterialRenderer
{
    sprite: Sprite;
    sphere: Mesh;
    scene: Scene;
    camera: Camera;
    canvas: HTMLCanvasElement;
    renderer: WebGLRenderer;
    constructor()
    {
        //Renderer
        this.renderer = new WebGLRenderer({ alpha: true, antialias: true });
        this.renderer.setSize(300, 300);

        //Canvas
        this.canvas = this.renderer.domElement;

        //Camera
        this.camera = new OrthographicCamera(-1, 1, 1, -1, -1, 1);

        //Scene
        this.scene = new Scene();

        //Sphere
        this.sphere = new Mesh(new BoxBufferGeometry(2, 2, 2));
        this.scene.add(this.sphere);

        //Sprite
        this.sprite = new Sprite();
        this.sprite.scale.set(2, 2, 1);
        this.scene.add(this.sprite);

        //Ambient light
        var ambient = new AmbientLight();
        this.scene.add(ambient);

        // 这个点光源会导致生成的缩略图上有一个高光
        // //Pontual light
        // var point = new PointLight();
        // point.position.set(-0.5, 1, 1.5);
        // this.scene.add(point);
    }

    //Set render size
    setSize(x: number, y: number)
    {
        this.renderer.setSize(x, y);
    }

    update(material: Material)
    {
        //Set material
        if (material instanceof SpriteMaterial)
        {
            this.sphere.visible = false;
            this.sprite.visible = true;

            this.sprite.material = material;
            this.camera.position.set(0, 0, 0.5);
        }
        else
        {
            this.sprite.visible = false;
            this.sphere.visible = true;

            this.sphere.material = material as MeshPhysicalMaterial;
            this.camera.position.set(0, 0, 1.5);
        }

        this.camera.updateMatrix();

        //Render
        this.renderer.render(this.scene, this.camera);
    }

    getBlob(material: Material): Promise<Blob>
    {
        this.update(material);
        return new Promise(res =>
        {
            this.canvas.toBlob(b => res(b));
        });
    }

    render(material: Material)
    {
        this.update(material);

        return this.canvas.toDataURL();
    };
}

export const materialRenderer = new MaterialRenderer();