import {Color3, Material, Mesh, MeshBuilder, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core";
import axios from "axios";
import {AdvancedDynamicTexture, TextBlock} from "@babylonjs/gui";

export class NewRelicQuery {
    private readonly scene: Scene;
    private data: { name: string, point: Vector3 }[] = [];
    private baseTransform: TransformNode;
    private seriesNumber = 0;
    private maxY = 0;
    private minY = 0;
    private maxZ = 0;
    private minZ = 0;

    constructor(scene: Scene) {
        this.scene = scene;
        this.baseTransform = new TransformNode("graphBase", this.scene);
    }

    public async getSales() {
        const data = await axios.get('/data.json')
        const series = data.data[0].series[0].series;
        for (const s of series) {
            this.buildSeries(s);
        }
        this.buildModel();
        console.log(this.data.length);
    }

    //private materials: Material[];
    private buildSeries(series) {
        const name = series.name;
        const material = new StandardMaterial(name + 'Material', this.scene);
        material.diffuseColor = new Color3(Math.random(), Math.random(), Math.random());
        //material.ambientColor = new Color3(0, 0, 0);
        material.specularColor = new Color3(1, 1, 1);
        material.alpha = .9;


        //this.materials.push(material);
        const data = series.data;
        for (const point in data) {
            this.buildPoint(name, data[point]);

        }
        this.buildTextLabel(name, new Vector3(this.seriesNumber, .25, -.25));
        this.seriesNumber++;

    }

    private buildTextLabel(text: string, position: Vector3) {

        const plane = MeshBuilder.CreatePlane("plane", {width: .5, height: .25}, this.scene);
        plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
        const advancedTexture = AdvancedDynamicTexture.CreateForMesh(plane, 1024, 512, false);
        var text1 = new TextBlock();
        text1.text = text;
        advancedTexture.background = "#000000";
        text1.color = "white";
        text1.fontSize = 128;
        advancedTexture.addControl(text1);
        plane.position.set(position.x, position.y, position.z);
    }

    private buildNumericLabel(number: number, position: Vector3) {
        const rounded = Math.round(number);
        let shortNumber: string = '???';
        if (Math.log10(rounded) < 3) {
            shortNumber = rounded.toString();
        }
        if (Math.log10(rounded) >= 3 && Math.log10(rounded) < 6) {
            shortNumber = (Math.round(rounded / 100) / 10).toString() + 'K';
        }
        if (Math.log10(rounded) >= 6) {
            shortNumber = (Math.round(rounded / 100000) / 10).toString() + 'M';
        }
        this.buildTextLabel(shortNumber, position);
    }

    private buildModel() {
        const zScale = 20 / (this.maxZ - this.minZ);
        const yScale = 20 / (this.maxY - this.minY);
        for (const point of this.data) {
            const z = (point.point.z - this.minZ) * zScale;
            const y = (point.point.y - this.minY) * yScale;
            //const baseMesh = (this.scene.getMeshByName(point.name+ 'Mesh') as Mesh);
            const bar = MeshBuilder.CreateBox(name + 'Mesh', {width: 1, height: 1, depth: 1}, this.scene);
            bar.material = this.scene.getMaterialByName(point.name + 'Material');

            //const bar = new InstancedMesh(point.name + point.point.z, baseMesh);
            bar.scaling.x = .5;
            bar.scaling.y = y;
            bar.scaling.z = .5;
            /*MeshBuilder.CreateBox(point.name + point.point.z, {width: .5,
            height: y, depth: .5}, this.scene);
*/
            bar.position.set(point.point.x, y / 2, z);
            this.buildNumericLabel(point.point.y, new Vector3(point.point.x, y, z));
            const base = MeshBuilder.CreatePlane('base', {width: 20, height: 20}, this.scene);
            const material = new StandardMaterial("baseMaterial", this.scene);
            material.diffuseColor = new Color3(0, 1, 0);
            base.material = material;
            base.position.set(10, .001, 10);
            base.parent = this.baseTransform;
            base.rotation.x = Math.PI / 2;
            bar.parent = this.baseTransform;

            // bar.material = this.scene.getMaterialByName(point.name+'Material');
        }

    }

    private buildPoint(name, point) {
        if (point[1] > this.maxY) {
            this.maxY = point[1];
        }
        if (this.minY === 0 || point[1] < this.minY) {
            this.minY = point[1];
        }
        if (point[0] > this.maxZ) {
            this.maxZ = point[0];
        }
        if (this.minZ === 0 || point[0] < this.minZ) {
            this.minZ = point[0];
        }
        this.data.push({name: name, point: new Vector3(this.seriesNumber, point[1], point[0])});
    }
}