import { vec3 } from "gl-matrix";
import { Box3, MeshStandardMaterial, PlaneBufferGeometry, Sphere } from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { Color } from "../../../../core/color/Color.js";
import { kelvin_to_rgb } from "../../../../core/color/kelvin/kelvin_to_rgb.js";
import { noop } from "../../../../core/function/noop.js";
import Quaternion from "../../../../core/geom/Quaternion.js";
import Vector3 from "../../../../core/geom/Vector3.js";
import { Transform } from "../../../ecs/transform/Transform.js";
import { DirectionalLight } from "../../render/forward_plus/model/DirectionalLight.js";
import { three_object_replace_materials } from "../../three/three_object_replace_materials.js";
import { three_object_to_path_traced_scene } from "./three_object_to_path_traced_scene.js";

export function make_sun({
                             temperature = 5000, // around clear-sky day
                             color = '#FFFFFF',
                             intensity = 1,
                             direction = new Vector3(-0.5, -1, -0.05)
                         } = {}) {

    const temp_c = new Color();

    kelvin_to_rgb(temp_c, 0, temperature);

    const light = new DirectionalLight();

    light.color.parse(color);
    vec3.multiply(light.color, light.color, temp_c);

    const n = vec3.length(light.color);
    vec3.scale(light.color, light.color, 1 / n); // normalize color vector

    light.intensity.set(intensity * n);
    light.direction.copy(direction);
    light.direction.normalize();


    return light;
}

/**
 *
 * @param {string} url
 * @return {Promise<GLTF>}
 */
function promise_gltf(url) {
    return new Promise((resolve, reject) => {
        new GLTFLoader().load(url, resolve, noop, reject);
    });
}

/**
 *
 * @param {PathTracedScene} scene
 * @param {THREE.Camera} camera
 * @param {string} url
 * @param {number} [zoom]
 * @param {number} [floor_level]
 * @param {Object} [sun]
 * @param {boolean} [no_materials]
 * @return {Promise<void>}
 */
export async function prepare_scene_gltf({
                                             scene,
                                             camera,
                                             url,
                                             zoom = 1,
                                             floor_level = 0,
                                             sun,
                                             no_materials = false
                                         }) {
    const gltf = await promise_gltf(url);


    const ground_material = new MeshStandardMaterial({
        color: '#ffceae'
    });
    scene.createMesh(new PlaneBufferGeometry(), ground_material, Transform.fromJSON({
        position: new Vector3(0, floor_level, 0),
        scale: 5000,
        rotation: Quaternion.fromEulerAngles(-Math.PI / 2, 0, 0)
    }).matrix);


    const gltf_scene = gltf.scene;

    if (no_materials) {
        three_object_replace_materials(gltf_scene, new MeshStandardMaterial({ color: 'white' }));
    }

    three_object_to_path_traced_scene(gltf_scene, scene);

    const box3 = new Box3();
    box3.setFromObject(gltf_scene);

    const sphere = new Sphere();

    box3.getBoundingSphere(sphere);

    scene.addLight(make_sun(sun));

    camera.position.set(1, 1.3, 1)
        .normalize()
        .multiplyScalar(sphere.radius * 2.6 * (1 / zoom));

    camera.lookAt(sphere.center);
}