import { ImprovedNoise } from "three/examples/jsm/math/ImprovedNoise.js";
import Vector2 from "../../src/core/geom/Vector2.js";
import Vector3 from "../../src/core/geom/Vector3.js";
import { lerp } from "../../src/core/math/lerp.js";
import { GameAssetType } from "../../src/engine/asset/GameAssetType.js";
import { TextureAssetLoader } from "../../src/engine/asset/loaders/texture/TextureAssetLoader.js";
import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
import { EngineConfiguration } from "../../src/engine/EngineConfiguration.js";
import { EngineHarness } from "../../src/engine/EngineHarness.js";

const eh = new EngineHarness();

/**
 *
 * @param {Engine} engine
 * @return {EngineConfiguration}
 */
function makeConfig(engine) {
    const r = new EngineConfiguration();

    // configure engine here, add systems, loaders etc.
    r.addLoader(GameAssetType.Texture, new TextureAssetLoader());

    return r;
}

/**
 *
 * @param {Terrain} terrain
 * @param {number} resolution
 * @param {number} heightMin
 * @param {number} heightMax
 */
async function buildRandomTerrainHeights({
                                             terrain,
                                             resolution = 64,
                                             heightMin = -5,
                                             heightMax = 20
                                         }) {

    const terrain_height = terrain.samplerHeight;

    terrain_height.resize(resolution, resolution);

    const noise = new ImprovedNoise();

    let x, y;

    for (y = 0; y < resolution; y++) {
        for (x = 0; x < resolution; x++) {

            const u = x / (resolution - 1);
            const v = y / (resolution - 1);

            const noise_value = noise.noise(u * 13.456, v * 13.456, 0) * noise.noise(u * 3.71, v * 3.71, 0.8);

            const height_value = lerp(heightMin, heightMax, noise_value);

            terrain_height.write(x, y, [height_value]);
        }
    }

    await terrain.updateWorkerHeights();
    terrain.updateHeightTexture();
    terrain.buildLightMap();

    terrain.__tiles.rebuild();
}

/**
 *
 * @param {Engine} engine
 */
async function main(engine) {


    await EngineHarness.buildBasics({
        engine,
        enableWater: false,
        terrainResolution: 4,
        terrainSize: new Vector2(64, 64),
        focus: new Vector3(64, 0, 54),
        yaw: 0,
        pitch: 0.909,
        distance: 169
    });

    /**
     *
     * @type {EntityComponentDataset}
     */
    const ecd = engine.entityManager.dataset;

    /**
     *
     * @type {Terrain|null}
     */
    const terrain = obtainTerrain(ecd);

    buildRandomTerrainHeights({ terrain: terrain });
}

/**
 *
 * @param {EngineHarness} harness
 */
async function init(harness) {
    const engine = eh.engine;

    await makeConfig(engine).apply(engine);

    await eh.initialize();

    main(engine);
}

init(eh);
