import { CylinderBufferGeometry, MeshStandardMaterial } from "three";
import { TransformControls } from "../../../../../editor/tools/v2/TransformControls.js";
import Vector3 from "../../../../core/geom/Vector3.js";
import { DEG_TO_RAD } from "../../../../core/math/DEG_TO_RAD.js";
import Entity from "../../../ecs/Entity.js";
import { TransformAttachmentSystem } from "../../../ecs/transform-attachment/TransformAttachmentSystem.js";
import { Transform } from "../../../ecs/transform/Transform.js";
import { EngineHarness } from "../../../EngineHarness.js";
import { ShadedGeometry } from "../../../graphics/ecs/mesh-v2/ShadedGeometry.js";
import { ShadedGeometrySystem } from "../../../graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
import InputController from "../../../input/ecs/components/InputController.js";
import InputControllerSystem from "../../../input/ecs/systems/InputControllerSystem.js";
import { BehaviorComponent } from "../../../intelligence/behavior/ecs/BehaviorComponent.js";
import { BehaviorSystem } from "../../../intelligence/behavior/ecs/BehaviorSystem.js";
import { fabrik_solve } from "./fabrik_solve.js";

EngineHarness.bootstrap({
    configuration(config, engine) {
        config.addSystem(new ShadedGeometrySystem(engine));
        config.addSystem(new InputControllerSystem(engine.devices));
        config.addSystem(new TransformAttachmentSystem());
        config.addSystem(new BehaviorSystem(engine));
    }
})
    .then(async engine => {

        const ecd = engine.entityManager.dataset;

        await EngineHarness.buildBasics({
            engine,
            cameraController: false
        });


        const controls = new TransformControls(engine.graphics.camera, engine.viewStack.el);

        /**
         *
         * @type {Entity[]}
         */
        const chain = [];


        const link_geometry = new CylinderBufferGeometry(1, 1, 2);
        link_geometry.rotateX(90 * DEG_TO_RAD);

        for (let i = 0; i < 50; i++) {

            const entity = new Entity()
                .add(Transform.fromJSON({
                    position: {
                        x: 10,
                        y: 0,
                        z: 10
                    },
                    scale: 0.1
                }));

                entity.add(ShadedGeometry.from(link_geometry, new MeshStandardMaterial()));

            chain.push(entity);

            entity.build(ecd);
        }

        controls.build(ecd);
        controls.attach(chain[chain.length - 1].id);

        const joints = chain.map(e => e.getComponent(Transform));
        const lengths = chain.map(x => 0.1);

        new Entity()
            .add(BehaviorComponent.loop(timeDelta => {
                const last = joints[joints.length - 1];
                const target = last.position.clone();

                for (let i = 0; i < joints.length; i++) {
                    // gravity
                    joints[i].position._add(0, -9 * timeDelta, 0);
                }


                fabrik_solve(
                    joints,
                    lengths,
                    new Vector3(10, 2, 10),
                    target
                );

                last.position.copy(target);
            }))
            .build(ecd);

        new Entity()
            .add(new InputController([{
                path: 'keyboard/keys/w/down',
                listener() {
                    controls.mode = "translate"
                }
            }, {
                path: 'keyboard/keys/e/down',
                listener() {
                    controls.mode = "scale"
                }
            }, {
                path: 'keyboard/keys/r/down',
                listener() {
                    controls.mode = "rotate"
                }
            }]))
            .build(ecd);
    });