// Global ATON

import { AppState, getSceneStatus, setSceneStatus } from "./state.js";
import { config } from "../config.js";

const material = {
    color: "#fff",
    //color: "#e6f2ff",
    emissive: true,
};

const Scene = {};

Scene.UI = {};

Scene.UI.domParser = new DOMParser;

/**
 * @todo Experimental...
 * @param {THREE.Object3D} object - A THREE Object3D instance
 */
Scene.showEdges = function(object) {
    const edgeMaterial = new THREE.LineBasicMaterial( { color: 0x000000 } );

    object.traverse(function(child) {
    
        if (child.isMesh) {
            let edges = new THREE.EdgesGeometry(child.geometry, 45);
            let line = new THREE.LineSegments(edges, edgeMaterial);
            child.add(line);
        
            console.log(child);
        }
    });
}

/**
 * @todo WIP!
 * Activate clipping plane
 */
Scene.activateClipper = function() {
    const geometry = new THREE.PlaneGeometry( 24, 24 );
    const material = new THREE.MeshPhongMaterial({
        color: 0xffffee,
        opacity: 0.5,
        transparent: true,
    });
    const plane = new THREE.Mesh( geometry, material );
    const root = AppState.root;
    console.log(root, plane);
    root.add(plane);
    AppState.clipping.enabled = true;
    AppState.clipping.plane = plane;
}

/**
 * 
 * @param {THREE.Vector3} vector - An object with x,y,z coordinates
 */
Scene.changeLightDirection = function(vector) {
    ATON.setMainLightDirection(vector);
}

/**
 * 
 * @param {Boolean} isEnabled 
 */
Scene.toggleAmbientOcclusion = function(isEnabled) {
    ATON.FX.togglePass(ATON.FX.PASS_AO, isEnabled);
    console.log('Ambient occlusion', isEnabled ? 'ON' : 'OFF');
}

/**
 * 
 * @param {String} direction - The axis direction, one of 'x','y','z'
 * @param {String} label - The slider label
 * @param {Number[]} range - The slider's range
 * @param {Number} step - The slider's step
 */
Scene.createLightSlider = function(direction, label, range, step) {
    const currentVal = ATON.getMainLightDirection()[direction];
    const lightSlider = ATON.UI.createSlider({
        range,
        label,
        value: Number.parseFloat(currentVal).toPrecision(1),
        oninput: val => {
            const lightDir = ATON.getMainLightDirection();
            // Keep existing direction values for the other axes
            lightDir[direction] = Number.parseFloat(val);
            this.changeLightDirection(lightDir);
        },
    });

    lightSlider.classList.add('ms-4');
    lightSlider.querySelector('input').step = step;

    return lightSlider;
}

/**
 * Right-side main menu panel
 * @param {String} triggerId - The menu button id
 */
Scene.toggleContentMenu = function(triggerId) {
    const btn = document.querySelector(`#${triggerId}`);
    const audio1 = this.UI.domParser.parseFromString(config.menu.audioBtn1, 'text/html')
        .querySelector('button');

    btn.addEventListener('click', () => {
        ATON.UI.setSidePanelRight();
        ATON.UI.showSidePanel({header: '<i class="bi bi-music-note-list me-1"></i> Contenuti'});
        ATON.UI.elSidePanel.appendChild(audio1);
    });
}

/**
 * A left side settings panel
 * @param {String} triggerId - The settings button id
 */
Scene.toggleSettingsPanel = function(triggerId) {
    const btn = document.querySelector(`#${triggerId}`);
    const lightHeading = document.createElement('h2');
    lightHeading.className = 'fs-5 ms-2 mb-3 mt-3';
    lightHeading.innerHTML = '<i class="bi bi-lightbulb me-1"></i> Direzione luce';
    const envHeading = document.createElement('h2');
    envHeading.className = 'fs-5 ms-2 mb-3 mt-3';
    envHeading.innerHTML = '<i class="bi bi-brightness-high me-1"></i> Ambiente';

    btn.addEventListener('click', () => {
        ATON.UI.setSidePanelLeft();
        ATON.UI.showSidePanel({header: '<i class="bi bi-gear-fill me-1"></i> Impostazioni'});
        ATON.UI.elSidePanel.appendChild(lightHeading);

        const lightSliderX = this.createLightSlider('x', 'Asse X', [-2, 2], 0.1);
        const lightSliderY = this.createLightSlider('y', 'Asse Y', [-2, 2], 0.1);
        const lightSliderZ = this.createLightSlider('z', 'Asse Z', [-2, 2], 0.1);

        ATON.UI.elSidePanel.appendChild(lightSliderX);
        ATON.UI.elSidePanel.appendChild(lightSliderY);
        ATON.UI.elSidePanel.appendChild(lightSliderZ);

        ATON.UI.elSidePanel.appendChild(envHeading);

        const ambientOcclSwitch = document.createElement('div');
        ambientOcclSwitch.className = 'form-check form-switch ms-4 mt-2';
        ambientOcclSwitch.innerHTML = `
            <input class="form-check-input" type="checkbox" role="switch" id="aoSwitch" title="Abilita / disabilita ambient occlusion">
            <label class="form-check-label" for="aoSwitch"><em>Ambient occlusion</em> <i class="bi bi-info-circle ms-2 c-hand"></i></label>
        `;

        const shadowsSwitch = document.createElement('div');
        shadowsSwitch.className = 'form-check form-switch ms-4 mt-2';
        shadowsSwitch.innerHTML = `
            <input class="form-check-input" type="checkbox" role="switch" id="shadowsSwitch" title="Abilita / disabilita ombre">
            <label class="form-check-label" for="shadowsSwitch">Ombre <i class="bi bi-info-circle ms-2 c-hand" title=""></i></label>
        `;

        shadowsSwitch.querySelector('input[type="checkbox"').checked = AppState.shadows;
        ambientOcclSwitch.querySelector('input[type="checkbox"').checked = AppState.ambientOcclusion;

        ATON.UI.elSidePanel.appendChild(ambientOcclSwitch);
        ATON.UI.elSidePanel.appendChild(shadowsSwitch);
        // TODO: move somewhere else...
        document.querySelector('#aoSwitch').addEventListener(
            'change',
            event => {
                this.toggleAmbientOcclusion(event.target.checked);
                AppState.ambientOcclusion = event.target.checked;
            }
        );
        document.querySelector('#shadowsSwitch').addEventListener(
            'change',
            event => {
                const checked = event.target.checked;
                ATON.toggleShadows(checked);
                AppState.shadows = checked;
            }
        );
    });
}

/**
 * @todo Get clipping button from state? Review logic!! 
 * @param {String} triggerSelector 
 */
Scene.UI.toggleClipper = function(triggerSelector) {
    const trigger = document.querySelector(triggerSelector);
    trigger.addEventListener(
        'click',
        () => {
            const aoCurrentState = AppState.ambientOcclusion;
            if (!AppState.clipping.enabled) {
                AppState.clipping.enabled = true;
                trigger.className += ' border border-2 border-white';
                Scene.toggleAmbientOcclusion(false);
                //Scene.activateClipper()
            } else {
                AppState.clipping.enabled = false;
                ATON.disableClipPlanes();
                AppState.root.remove(AppState.clipping.helper);
                AppState.clipping.helper = null;
                let noBorder = trigger.className.replace(/ border.*$/g, '');
                trigger.className = noBorder;
                Scene.toggleAmbientOcclusion(aoCurrentState);
            }
        }
    );
}

Scene.init = function() {
    console.log("I'm initializing, baby!")
    ATON.realize();
    ATON.UI.addBasicEvents();
    ATON.UI.init();
    // All assets for this app are stored here
    ATON.setPathCollection('./assets/');
    // Light direction should be dynamic / user-defined
    ATON.setMainLightDirection(new THREE.Vector3(0.2,-0.3,-0.7));

    ATON.toggleShadows(true);
    ATON.setExposure(0.8);
    // Open settings side panel when clicking on settings btn
    Scene.toggleSettingsPanel('settings');
    Scene.toggleContentMenu('menu');

    window.addEventListener('mousedown', event => {
        // Activate clipping when left-clicking on the scene
        if (AppState.clipping.enabled && event.buttons === 1) {
            const point = ATON.getSceneQueriedPoint();
            if (point) {
                // First remove any existing clipping planes
                ATON.disableClipPlanes();
                // Normal of the clipping plane along the Y axis facing down
                const plane = ATON.addClipPlane(new THREE.Vector3(0, -1, 0), point);
                // Add a visible plane helper for the clipping plane
                const helper = new THREE.PlaneHelper(plane, 24, 0xffff00);
                // Remove any already visbile helper plane
                if (AppState.clipping.helper !== null) AppState.root.remove(AppState.clipping.helper);
                AppState.root.add(helper);
                AppState.clipping.helper = helper;
                console.log("I'm clipping, baby!");
            }
        }
    });
}
/**
 * @param {String} id - The back-to-map button id
 */
Scene.toggleScene = function(id) {
    const btn = document.querySelector(`#${id}`);
    const scene = document.querySelector('#scene');

    btn.addEventListener('click', () => {
        scene.classList.toggle('d-none');
        // Pause rendering the 3D scene to free resources (hopefully)
        // when browsing the map
        ATON.renderPause();
        document.querySelector('#map').classList.toggle('d-none');
        AppState.map.invalidateSize();
    });
}
/**
 * @param {Object} marker - The marker object from config
 */
Scene.openScene = function(marker) {
    let canvas = document.querySelector('canvas');
    let scene = document.querySelector('#scene');

    if (canvas === null) {
        Scene.init();
    }

    scene.classList.toggle('d-none');
    ATON.renderResume();

    if (!getSceneStatus(marker.id)) {
        // Set scene as active
        setSceneStatus(marker.id, true);
        // Load 3D model
        let mainNode = ATON.createSceneNode(marker.label).load(marker.model);
        ATON.setMainPanorama(marker.pano);
        //mainNode.setMaterial(new THREE.MeshPhongMaterial(material));
        mainNode.setRotation(0, 1.5, 0)
        Scene.showEdges(mainNode);

        mainNode.attachToRoot();

        ATON.setAutoLP(true);
        Scene.toggleAmbientOcclusion(true);
        AppState.ambientOcclusion = true;

        Scene.UI.toggleClipper('#clipper');

        AppState.root = ATON.getRootScene();
    }
}

export default Scene;