import { EngineHarness } from "../../EngineHarness.js";
import { ShadedGeometrySystem } from "../../graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
import { Transform } from "../transform/Transform.js";
import { ShadedGeometry } from "../../graphics/ecs/mesh-v2/ShadedGeometry.js";
import { BoxBufferGeometry, MeshLambertMaterial } from "three";
import { EngineConfiguration } from "../../EngineConfiguration.js";
import { EntityNode } from "./EntityNode.js";
import { AttachmentSystem } from "../attachment/AttachmentSystem.js";
import { SurfacePoint3 } from "../../../core/geom/3d/SurfacePoint3.js";
import Vector3 from "../../../core/geom/Vector3.js";
import Vector2 from "../../../core/geom/Vector2.js";
import { FaceEditor, STATE_EDIT, STATE_HOVER } from "./FaceEditor.js";

const eh = new EngineHarness();

function makeConfig(engine) {
    const r = new EngineConfiguration();

    r.addSystem(new ShadedGeometrySystem(engine));
    r.addSystem(new AttachmentSystem())

    return r;
}

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


    EngineHarness.buildBasics({ engine, enableWater: false })


    const ecd = engine.entityManager.dataset;

    const block_a = EntityNode.fromComponents(
        ShadedGeometry.from(new BoxBufferGeometry(), new MeshLambertMaterial({
            color: 0xFFFFAA
        })),
        new Transform()
    );

    block_a.transform.position.set(5, 0.5, 5);

    const block_b = EntityNode.fromComponents(
        ShadedGeometry.from(new BoxBufferGeometry(), new MeshLambertMaterial({
            color: 0xAAFFFF
        })),
        new Transform()
    );

    block_b.transform.position.set(1, 1, 1);
    block_a.addChild(block_b);

    block_a.build(ecd);

    function pick(x, y) {
        /**
         *
         * @type {ShadedGeometrySystem|null}
         */
        const system = engine.entityManager.getSystem(ShadedGeometrySystem);

        const contact = new SurfacePoint3();

        const origin = new Vector3();
        const direction = new Vector3();

        const p = new Vector2(x, y);
        const point_2 = p.clone();

        engine.graphics.normalizeViewportPoint(p, point_2);
        engine.graphics.viewportProjectionRay(point_2.x, point_2.y, origin, direction);

        const hit = system.raycastNearest(contact, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z);

        if (hit === undefined) {
            return;
        }

        return Object.assign({ contact }, hit);
    }

    const editor = new FaceEditor();

    function update_hover_state(x, y) {
        const hit = pick(x, y);

        if (hit === undefined) {
            editor.detach();
        } else {
            if (editor.mesh !== hit.mesh) {
                editor.detach();

                editor.contact = hit.contact;
                editor.mesh = hit.mesh;
                editor.entity = hit.entity;
                editor.ecd = ecd;

                editor.attach();
                editor.state = STATE_HOVER;
            } else {
                // update contact only
                editor.contact = hit.contact;
            }

        }

    }

    engine.devices.pointer.position.onChanged.add((x, y) => {
        if (editor.state !== STATE_EDIT) {
            update_hover_state(x, y);

        } else {

        }
    });


    engine.devices.pointer.on.dragStart.add((p) => {
        if (editor.state === STATE_HOVER) {
            editor.edit_anchor_point = editor.contact.position;
            editor.state = STATE_EDIT;
        }
    });
    engine.devices.pointer.on.drag.add(p => {
        editor.edit_target_point = p;
    });
    engine.devices.pointer.on.dragEnd.add(p => {
        if (editor.state === STATE_EDIT) {
            update_hover_state(p.x, p.y);
        }
    });

}

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

    await makeConfig(engine).apply(engine);

    await eh.initialize();

    main(engine);
}

init(eh);
