import { makeEngineOptionsModel } from "../../../../../../../model/game/options/makeEngineOptionsModel.js";
import { enableEditor } from "../../../../../../editor/enableEditor.js";
import Vector2 from "../../../../../core/geom/Vector2.js";
import Vector3 from "../../../../../core/geom/Vector3.js";
import { create_simplex_noise_2d } from "../../../../../core/math/noise/create_simplex_noise_2d.js";
import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
import ViewportPositionSystem from "../../../../ecs/gui/position/ViewportPositionSystem.js";
import RenderSystem from "../../../../ecs/systems/RenderSystem.js";
import ScriptSystem from "../../../../ecs/systems/ScriptSystem.js";
import TimerSystem from "../../../../ecs/systems/TimerSystem.js";
import TerrainSystem from "../../../../ecs/terrain/ecs/TerrainSystem.js";
import { obtainTerrain } from "../../../../ecs/terrain/util/obtainTerrain.js";
import { EngineConfiguration } from "../../../../EngineConfiguration.js";
import { EngineHarness } from "../../../../EngineHarness.js";
import { GridPosition2TransformSystem } from "../../../../grid/grid2transform/GridPosition2TransformSystem.js";
import GridPositionSystem from "../../../../grid/position/GridPositionSystem.js";
import { Transform2GridPositionSystem } from "../../../../grid/transform2grid/Transform2GridPositionSystem.js";
import InputControllerSystem from "../../../../input/ecs/systems/InputControllerSystem.js";
import { InputSystem } from "../../../../input/ecs/systems/InputSystem.js";
import PathFollowingSystem from "../../../../navigation/ecs/path_following/PathFollowingSystem.js";
import { CameraSystem } from "../../camera/CameraSystem.js";
import TopDownCameraControllerSystem from "../../camera/topdown/TopDownCameraControllerSystem.js";
import { TopDownCameraLanderSystem } from "../../camera/topdown/TopDownCameraLanderSystem.js";
import MeshHighlightSystem from "../../highlight/system/MeshHighlightSystem.js";
import LightSystem from "../../light/LightSystem.js";
import { MeshSystem } from "../../mesh/MeshSystem.js";
import WaterSystem from "../../water/WaterSystem.js";

const engineHarness = new EngineHarness();

function makeConfig(engine) {

    const config = new EngineConfiguration();

    const graphics = engine.graphics;
    const assetManager = engine.assetManager;
    const devices = engine.devices;

    config.addManySystems(
        new ScriptSystem(),
        new PathFollowingSystem(),
        new TimerSystem(),
        new TopDownCameraControllerSystem(graphics),
        new TopDownCameraLanderSystem(),
        new CameraSystem(engine.graphics),
        new MeshSystem(graphics, assetManager),
        new TerrainSystem(graphics, assetManager),
        new WaterSystem(graphics),
        new ViewportPositionSystem(graphics.viewport.size),
        new GridPosition2TransformSystem(),
        new Transform2GridPositionSystem(),
        new GridPositionSystem(),
        new InputControllerSystem(devices),
        new InputSystem(devices),
        new MeshHighlightSystem(engine),
        new LightSystem(engine, {
            shadowResolution: 1024
        }),
    );

    // Plugins


    // Knowledge

    config.knowledge.push();

    return config;
}


/**
 *
 * @param {EngineHarness} harness
 * @return {Promise<void>}
 */
async function init(harness) {
    const engine = harness.engine;

    engine.entityManager.addSystem(new RenderSystem(engine.graphics));

    makeEngineOptionsModel(engine.options, engine);

    await makeConfig(engine).apply(engine);

    enableEditor(engine);

    await harness.initialize();

    main(engine);
}

/**
 *
 * @param {Terrain} terrain
 * @param {number} seed
 */
function seedTerrain(terrain, seed) {

    const height = terrain.samplerHeight;

    height.resize(50, 50);

    const w = height.width;
    const h = height.height;

    const random = seededRandom(seed);

    const noise = create_simplex_noise_2d(random);

    for (let i = 0; i < w; i++) {
        const u = i / 20;
        for (let j = 0; j < h; j++) {
            const v = j / 20;

            const noise_value_0 = noise(u, v);

            const noise_value_1 = noise(u * 0.17 + 0.1231, v * 0.17 + 0.1231);

            const noise_final = noise_value_0 * 0.7 + noise_value_1 * 0.3;

            height.writeChannel(i, j, 0, noise_final * 15);
        }
    }

    terrain.updateHeightTexture();
    terrain.updateWorkerHeights();
}

/**
 *
 * @param {Engine} engine
 */
function main(engine) {
    EngineHarness.buildBasics({
        engine,
        enableWater: true,
        terrainSize: new Vector2(100, 100),
        focus: new Vector3(102, 0, 61),
        pitch: -0.98,
        yaw: 2.3,
        distance: 100
        // pitch: -0.12,
        // yaw: 3.1,
        // distance: 5
    });

    const em = engine.entityManager;

    const terrain = obtainTerrain(em.dataset);

    seedTerrain(terrain, 42);
}

init(engineHarness);
