import { BoxGeometry, Mesh, MeshStandardMaterial, Group, Vector3, CatmullRomCurve3} from 'three';
import { LineMaterial, LineGeometry, Line2 } from 'three/examples/jsm/Addons.js';
import { EventManager } from '@/lib/EventManager';
import Utils from '#/app/Utils';

class PairMatchingGame extends EventManager {
    emits = ['finish', 'interaction']
    constructor(engine, data) {
        super();
        return new Promise(async (resolve, reject)=>{
            let container = new Group();
            let c = data.c, orderArray = Array.from({length:c}, (_, i)=>i);
            let o = [ Utils.shuffleArray(orderArray), Utils.shuffleArray(orderArray) ]
            const aq = engine.motionQueue;
            let dx = 3, dy = 1.2;

            let bm = new BoxGeometry(1, 1, 1);

            let material = new MeshStandardMaterial({
                map: await engine.loadTexture(data.$go.asset.name),
                alphaTest: 0.5,
                emissive: 0x00ff00,
                emissiveIntensity: 0
                // roughness:1, metalness:0,
                // normalMap: await engine.loadTexture('NormalMap.png', '/static/textures/'),
            });
            //material.map.encoding = sRGBEncoding;

            for (let i = 0; i < c; i++) {
                let b = [], uv = [], p = [];
                for (let xi = 0; xi < 2; xi++){
                    b[xi] = bm.clone();
                    uv[xi] = b[xi].getAttribute('uv');
                    let s = [xi/2, i / c];
                    for (let i = 0; i < 6; i++) {
                        //top left
                        uv[xi].array[8 * i] = s[0];
                        uv[xi].array[8 * i + 1] = s[1] + 1 / c;
                        //top right
                        uv[xi].array[8 * i + 2] = s[0] + 1 / 2;
                        uv[xi].array[8 * i + 3] = s[1] + 1 / c;
                        //bottom left
                        uv[xi].array[8 * i + 4] = s[0];
                        uv[xi].array[8 * i + 5] = s[1];
                        //bottom right
                        uv[xi].array[8 * i + 6] = s[0] + 1 / 2;
                        uv[xi].array[8 * i + 7] = s[1];
                    }
                    let mesh = new Mesh(b[xi], material.clone());
                    mesh.position.set(xi * dx + Math.random() * (xi+0.5) * dx, o[xi][i] * dy, Math.random() * (xi+0.5) * dx);
                    mesh.userData.gd = {
                        pair: xi,
                        id: i
                    }
                    container.add(mesh);
                }
            }

            let clicked, done = [];

            let connect = (a, b)=>{
                let crc = new CatmullRomCurve3([
                    a.position,
                    new Vector3().copy(a.position).lerpVectors(a.position, b.position, 0.5).multiplyScalar(1 + Math.random() * 0.1 * done.length / c),
                    b.position
                ])
                let g = new LineGeometry().setFromPoints( crc.getPoints(7) );
                let m = new Line2(g, new LineMaterial( {
					color: 0x00FF00,
					linewidth: 5, // in world units with size attenuation, pixels otherwise
				} ));
                container.add(m)
            }

            let actionDef = {material:{emissiveIntensity:k=>Math.max(0, Math.sin((k * 2 + 1.5) * Math.PI)) * 1 }};

            var clickFn = (i) => {
                this.dispatchEvent({type:'interaction'});
                let oc = clicked;
                if (done.includes(i.object.userData.gd.id)) return;
                clicked = i.object;
                clicked.material.emissive.setHex(0x00ff00);
                if (oc && oc.userData.gd.pair != clicked.userData.gd.pair){
                    if (oc.userData.gd.id === clicked.userData.gd.id){
                        connect(oc, clicked);
                        done.push(oc.userData.gd.id)
                        if (done.length == c) {
                            this.dispatchEvent({type:'finish'})
                        }
                    }else{
                        clicked.material.emissive.setHex(0xff0000);
                        oc.material.emissive.setHex(0xff0000);
                    }
                    aq.clear(oc, true);
                    aq.add({ o: clicked, a: actionDef, t: 1 });
                    aq.add({ o: oc, a: actionDef, t: 1 });
                    clicked = null;
                }else{
                    aq.clear(oc, true);
                    aq.add({ o: clicked, a: actionDef, t: 1, r: true })
                }
            };

            container.children.forEach(c => {
                engine.clickable.add(c, clickFn);
            });

            this.update = () => {
                
            };

            this.object = engine.meshUtils.centerOrigin(container);

            this.dispose = () => {
                engine.meshUtils.clearMaterial(material);
                bm.dispose();
                super.dispose();
            }

            resolve(this);
        })
    }
}

export { PairMatchingGame }