import Army from "../../../../../model/game/ecs/component/army/Army.js";
import {
    initializeGameBinarySerializationRegistry
} from "../../../../../model/game/GameBinarySerializationRegistry.js";
import { enableEditor } from "../../../../editor/enableEditor.js";
import Vector2 from "../../../core/geom/Vector2.js";
import { ArrayBufferLoader } from "../../asset/loaders/ArrayBufferLoader.js";
import { AttachmentSystem } from "../../ecs/attachment/AttachmentSystem.js";
import { SerializationMetadata } from "../../ecs/components/SerializationMetadata.js";
import Entity from "../../ecs/Entity.js";
import GUIElement from "../../ecs/gui/GUIElement.js";
import GUIElementSystem from "../../ecs/gui/GUIElementSystem.js";
import HeadsUpDisplaySystem from "../../ecs/gui/hud/HeadsUpDisplaySystem.js";
import ViewportPosition from "../../ecs/gui/position/ViewportPosition.js";
import ViewportPositionSystem from "../../ecs/gui/position/ViewportPositionSystem.js";
import AnimationSystem from "../../ecs/systems/AnimationSystem.js";
import ClingToTerrainSystem from "../../ecs/terrain/ecs/cling/ClingToTerrainSystem.js";
import TerrainSystem from "../../ecs/terrain/ecs/TerrainSystem.js";
import { EngineConfiguration } from "../../EngineConfiguration.js";
import { EngineHarness } from "../../EngineHarness.js";
import InputControllerSystem from "../../input/ecs/systems/InputControllerSystem.js";
import { InputSystem } from "../../input/ecs/systems/InputSystem.js";
import { BehaviorSystem } from "../../intelligence/behavior/ecs/BehaviorSystem.js";
import { loadSerializedScene } from "../../scene/SerializedScene.js";
import { SoundEmitterSystem } from "../../sound/ecs/emitter/SoundEmitterSystem.js";
import SoundControllerSystem from "../../sound/ecs/SoundControllerSystem.js";
import SoundListenerSystem from "../../sound/ecs/SoundListenerSystem.js";
import { CameraSystem } from "../ecs/camera/CameraSystem.js";
import TopDownCameraControllerSystem from "../ecs/camera/topdown/TopDownCameraControllerSystem.js";
import MeshHighlightSystem from "../ecs/highlight/system/MeshHighlightSystem.js";
import LightSystem from "../ecs/light/LightSystem.js";
import { ShadedGeometrySystem } from "../ecs/mesh-v2/ShadedGeometrySystem.js";
import Mesh from "../ecs/mesh/Mesh.js";
import { MeshSystem } from "../ecs/mesh/MeshSystem.js";
import { PathDisplaySystem } from "../ecs/path/PathDisplaySystem.js";
import Trail2DSystem from "../ecs/trail2d/Trail2DSystem.js";
import WaterSystem from "../ecs/water/WaterSystem.js";
import { ParticleEmitterSystem } from "../particles/ecs/ParticleEmitterSystem.js";
import { buildCanvasViewFromTexture } from "../render/visibility/hiz/buildCanvasViewFromTexture.js";

const eh = new EngineHarness();

/**
 *
 * @param {Engine} engine
 * @returns {EngineConfiguration}
 */
function makeConfig(engine) {

    const config = new EngineConfiguration();

    /**
     *
     * @type {SoundEngine}
     */
    const sound = engine.sound;
    const graphics = engine.graphics;
    const assetManager = engine.assetManager;
    const devices = engine.devices;

    // graphics.renderer.shadowMap.type = BasicShadowMap;

    const guiSystem = new GUIElementSystem(engine.gui.view, engine);
    const headsUpDisplaySystem = new HeadsUpDisplaySystem(graphics);

    config.addLoader('arraybuffer', new ArrayBufferLoader());

    initializeGameBinarySerializationRegistry(engine.binarySerializationRegistry);

    config.addManySystems(
        new AttachmentSystem(),
        new SoundEmitterSystem(assetManager, sound.destination, sound.context),
        new SoundControllerSystem(),
        new SoundListenerSystem(sound.context),
        guiSystem,
        new AnimationSystem(graphics.viewport.size),
        new TopDownCameraControllerSystem(graphics),
        new CameraSystem(engine.graphics),
        new MeshSystem(engine),
        new ClingToTerrainSystem(),
        new TerrainSystem(graphics, assetManager),
        new Trail2DSystem(engine),
        new ViewportPositionSystem(graphics.viewport.size),
        new InputControllerSystem(devices),
        new InputSystem(devices),
        new MeshHighlightSystem(engine),
        new LightSystem(engine, {
            shadowResolution: 2048
        }),
        headsUpDisplaySystem,
        new BehaviorSystem(engine),
        new PathDisplaySystem(engine),
        new ParticleEmitterSystem(engine),
        new ShadedGeometrySystem(engine),
        new WaterSystem(graphics)
    );


    // Knowledge

    return config;
}

/**
 *
 * @param {Engine} engine
 */
function get_three_light(engine) {

    return engine.graphics.scene.children.find(l => l.isDirectionalLight);
}

/**
 *
 * @param {Engine} engine
 */
function init_shadowmap_preview(engine) {
    const ecd = engine.entityManager.dataset;

    const graphics = engine.graphics;
    const preview = buildCanvasViewFromTexture({
        width: 512,
        height: 512,
        renderer: graphics.renderer,
        texture: null
    });

    graphics.on.postOpaquePass.add(() => {

        const light = get_three_light(engine);

        if (light !== undefined) {
            preview.texture = light.shadow.map.texture;

            preview.render();
        }
    });


    new Entity()
        .add(ViewportPosition.fromJSON({
            offset: new Vector2(10, 10)
        }))
        .add(GUIElement.fromView(preview.view))
        .add(SerializationMetadata.Transient)
        .build(ecd);
}

/**
 *
 * @param {Engine} engine
 * @returns {Promise<void>}
 */
async function main(engine) {

    const ecd = engine.entityManager.dataset;
    await loadSerializedScene('data/levels/character_creation/level.bin', ecd, engine);


    const character = ecd.getAnyComponent(Army);

    const entity = Entity.readFromDataset(character.entity, ecd);

    entity.getComponent(Mesh).url = "data/models/Conqueror Mech/Conqueror Mech.gltf";

    init_shadowmap_preview(engine);

    window.light = get_three_light(engine);
}

async function init(engineHarness) {

    const engine = await engineHarness.initialize();

    const config = makeConfig(engine);

    await config.apply(engine);

    enableEditor(engine);

    main(engine);
}

init(eh);
