import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { IJeelizFaceFilter } from 'vendors/jeelizFaceFilter/typescript/JeelizFaceFilterInterfaces';
import { SocialSharing } from '@ionic-native/social-sharing/ngx';

declare var JEELIZFACEFILTER: IJeelizFaceFilter;
declare var JeelizThreeHelper: any;
declare var JeelizResizer: any;
declare var THREE: any;

@Component({
    selector: 'app-ar-fan-cam',
    templateUrl: './ar-fan-cam.page.html',
    styleUrls: ['./ar-fan-cam.page.scss'],
})
export class ArFanCamPage implements OnInit {
    @ViewChild('sourceCanvasElement') sourceCanvasElement: ElementRef<HTMLCanvasElement>;

    THREECAMERA = null;

    width: number;
    height: number;

    camLoaded: boolean = false;

    tempImg = '';

    glassesFramesMeshLoaded: boolean = false;
    glassesLensMeshLoaded: boolean = false;

    constructor(
        private modalController: ModalController,
        private socialSharing: SocialSharing
    ) {
    }

    back() {
        JEELIZFACEFILTER.destroy();
        this.camLoaded = false;
        this.modalController.dismiss();
    }

    // AR Face detection and drawing

    detect_callback(faceIndex, isDetected) {
        if (isDetected) {
            console.log('INFO in detect_callback(): DETECTED');
        } else {
            console.log('INFO in detect_callback(): LOST');
        }
    }
    
    // build the 3D. called once when Jeeliz Face Filter is OK
    init_threeScene(spec) {
        const threeStuffs = JeelizThreeHelper.init(spec, this.detect_callback);
    
        // improve WebGLRenderer settings:
        threeStuffs.renderer.toneMapping = THREE.ACESFilmicToneMapping;
        threeStuffs.renderer.outputEncoding = THREE.sRGBEncoding;
    
        // CREATE THE GLASSES AND ADD THEM
        const r = this.JeelizThreeGlassesCreator({
            envMapURL: "assets/ar-accessories/envMap.jpg",
            frameMeshURL: "assets/ar-accessories/models3D/glassesFramesBranchesBent.json",
            lensesMeshURL: "assets/ar-accessories/models3D/glassesLenses.json",
            occluderURL: "assets/ar-accessories/models3D/face.json"
        });
    
        // vertical offset:
        const dy = 0.07;
    
        // create and add the occluder:
        r.occluder.rotation.set(0.3, 0, 0);
        r.occluder.position.set(0, 0.03 + dy,-0.04);
        r.occluder.scale.multiplyScalar(0.0084);
        threeStuffs.faceObject.add(r.occluder);
        
        // create and add the glasses mesh:
        const threeGlasses = r.glasses;
        //threeGlasses.rotation.set(-0.15,0,0); / /X neg -> rotate branches down
        threeGlasses.position.set(0, dy, 0.4);
        threeGlasses.scale.multiplyScalar(0.006);
        threeStuffs.faceObject.add(threeGlasses);
    
        // add a debug cube:
        /* const sc = 0.1;
        const debugCube = new THREE.Mesh(new THREE.BoxGeometry(sc,sc,sc), new THREE.MeshNormalMaterial());
        threeStuffs.faceObject.add(debugCube); //*/
    
        // CREATE THE CAMERA:
        this.THREECAMERA = JeelizThreeHelper.create_camera();
    }

    JeelizThreeGlassesCreator(spec) {
        const threeGlasses = new THREE.Object3D();
        
        // envMap texture:
        const textureEquirec = new THREE.TextureLoader().load( spec.envMapURL );
        textureEquirec.mapping = THREE.EquirectangularReflectionMapping;
        textureEquirec.magFilter = THREE.LinearFilter;
        textureEquirec.minFilter = THREE.LinearMipMapLinearFilter;
    
        // glasses frames:
        new THREE.BufferGeometryLoader().load(spec.frameMeshURL, function(glassesFramesGeometry){
            glassesFramesGeometry.computeVertexNormals();
        
            // custom material with fading at the end of the branches:
            const us = THREE.ShaderLib.standard.uniforms;
            const uniforms = {
                roughness: {value: 0},
                metalness: {value: 0.05},
                reflectivity: {value: 1},
                envMap: {value: textureEquirec},
                envMapIntensity: {value: 1},
                diffuse: {value: new THREE.Color().setHex(0xffffff)},
                uBranchFading: {value: new THREE.Vector2(-90, 60)} // first value: position (lower -> to the back), second: transition brutality
            };
        
            // tweak vertex shader to give the Z of the current point:
            let vertexShaderSource = "varying float vPosZ;\n" + THREE.ShaderLib.standard.vertexShader;
            vertexShaderSource = vertexShaderSource.replace('#include <fog_vertex>', 'vPosZ = position.z;');
        
            // tweak fragment shader to apply transparency at the end of the branches:
            let fragmentShaderSource = "uniform vec2 uBranchFading;\n varying float vPosZ;\n" + THREE.ShaderLib.standard.fragmentShader;
            const GLSLcomputeAlpha = 'gl_FragColor.a = smoothstep(uBranchFading.x - uBranchFading.y*0.5, uBranchFading.x + uBranchFading.y*0.5, vPosZ);'
            fragmentShaderSource = fragmentShaderSource.replace('#include <fog_fragment>', GLSLcomputeAlpha);
        
            const mat = new THREE.ShaderMaterial({
                vertexShader: vertexShaderSource,
                fragmentShader: fragmentShaderSource,
                uniforms: uniforms,
                flatShading: false,
                transparent: true,
                extensions: { // fix for https://github.com/jeeliz/jeelizFaceFilter/issues/154
                //derivatives: true,
                //shaderTextureLOD: true
                }
            });
        
            mat.envMap = textureEquirec;
            const glassesFramesMesh = new THREE.Mesh(glassesFramesGeometry, mat);
            threeGlasses.add(glassesFramesMesh);

            this.glassesFramesMeshLoaded = true;
        
            // window.debugMatFrames = mat; // to debug the material il the JS console
        });
    
        // glasses lenses:
        new THREE.BufferGeometryLoader().load(spec.lensesMeshURL, function(glassesLensesGeometry){
            glassesLensesGeometry.computeVertexNormals();
            const mat = new THREE.MeshBasicMaterial({
                envMap: textureEquirec,
                opacity: 0.7,
                color: new THREE.Color().setHex(0x2233aa),
                transparent: true,
                fog: false
            });
            const glassesLensesMesh = new THREE.Mesh(glassesLensesGeometry, mat);
            threeGlasses.add(glassesLensesMesh);

            this.glassesLensMeshLoaded = true;
        
            // window.debugMatLens = mat; // to debug the material il the JS console
        });
    
        const occluderMesh = JeelizThreeHelper.create_threejsOccluder(spec.occluderURL);
        
        return {
            glasses: threeGlasses,
            occluder: occluderMesh
        };
    }
    

    main(){
        JeelizResizer.size_canvas({
            canvasId: 'source-canvas',
            isApplyCSS: true,
            callback: (isError, bestVideoSettings) => {
                this.init_faceFilter(bestVideoSettings);
            }
        })
    }
    
    init_faceFilter(videoSettings){
        JEELIZFACEFILTER.init({
            followZRot: true,
            canvasId: 'source-canvas',
            NNCPath: 'assets/ar-accessories/neuralNets/', // root of NN_DEFAULT.json file
            maxFacesDetected: 1,
            videoSettings: {
                ...videoSettings,
                idealWidth: window.innerWidth,
                idealHeight: window.innerHeight,
                maxWidth: window.innerWidth,
                maxHeight: window.innerHeight,
            },
            callbackReady: (errCode, spec) => {
                if (errCode){
                    console.log('AN ERROR HAPPENS. ERR =', errCode);
                    return;
                }
            
                console.log('INFO: JEELIZFACEFILTER IS READY');
                this.camLoaded = true;
                this.init_threeScene(spec);
            },
        
            // called at each render iteration (drawing loop):
            callbackTrack: (detectState) => {
                JeelizThreeHelper.render(detectState, this.THREECAMERA);
            }
        }); //end JEELIZFACEFILTER.init call
    }

    // End AR Face detection and drawing

    async capture() {
        const dataURI = this.sourceCanvasElement.nativeElement.toDataURL('image/jpeg');
        this.tempImg = dataURI;
    }

    ngOnInit() {
        this.width = window.innerWidth;
        this.height = window.innerHeight;

        this.main();
    }

    approveImage() {
        
        this.modalController.dismiss({
            imageData: this.tempImg
        });        
    }


    shareVia(media: 'WhastApp' | 'Instagram' | 'Facebook' | 'others') {
        switch(media) {
            case 'WhastApp': this.socialSharing.shareViaWhatsApp('#SaddaPunjab, Download Punjab kings to checkout new filters', this.tempImg, ''); break;
            case 'Instagram': this.socialSharing.shareViaInstagram('#SaddaPunjab, Download Punjab kings to checkout new filters', this.tempImg); break;
            case 'Facebook': this.socialSharing.shareViaFacebook('#SaddaPunjab, Download Punjab kings to checkout new filters', this.tempImg, ''); break;
            case 'others': this.socialSharing.share('#SaddaPunjab, Download Punjab kings to checkout new filters', '', this.tempImg, ''); break;
            default: break;
        }
    }

}
