import { LineBasicMaterial } from "three";
import { makeHelperBoxGeometry } from "../../../../../../editor/process/symbolic/makeHelperBoxGeometry.js";
import { makeHelperSphereGeometry } from "../../../../../../editor/process/symbolic/makeHelperSphereGeometry.js";
import { Attachment } from "../../../../../engine/ecs/attachment/Attachment.js";
import Tag from "../../../../../engine/ecs/components/Tag.js";
import Entity from "../../../../../engine/ecs/Entity.js";
import { AttachmentSockets } from "../../../../../engine/ecs/sockets/AttachmentSockets.js";
import { Transform } from "../../../../../engine/ecs/transform/Transform.js";
import { DrawMode } from "../../../../../engine/graphics/ecs/mesh-v2/DrawMode.js";
import { ShadedGeometry } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometry.js";
import { SphereShape3D } from "../SphereShape3D.js";
import { TransformedShape3D } from "../TransformedShape3D.js";
import { UnionShape3D } from "../UnionShape3D.js";
import { UnitCubeShape3D } from "../UnitCubeShape3D.js";

const g_unit_sphere = makeHelperSphereGeometry(0.5, 32);
const g_unit_cube = makeHelperBoxGeometry(1, 1, 1);

const lineMaterial = new LineBasicMaterial({
    depthTest: true,
    depthWrite: false,
    transparent: true,
    linewidth: 1,
    fog: false,
    color: '#FFFFFF',
    opacity: 1
});

export const SHAPE_VISUAL_ENTITY_TAG = 'util/vis/Shape3D';

/**
 *
 * @param {UnionShape3D} shape
 * @param {EntityComponentDataset} ecd
 * @returns {Entity}
 */
function composite_shape_to_entity(shape, ecd) {

    const parent = new Entity();
    parent
        .add(new Transform())
        .add(AttachmentSockets.fromJSON({
            elements: [
                {
                    type: 0,
                    id: 0
                }
            ]
        }))
        .build(ecd);

    shape.children.forEach(c => {

        const child_entity = shape_to_visual_entity(c, ecd);

        child_entity.add(Attachment.fromJSON({
            socket: 0,
            parent: parent.id,
            immediate: true
        }));

    })

    return parent;
}


/**
 *
 * @param {UnitCubeShape3D} shape
 * @param {EntityComponentDataset} ecd
 * @returns {Entity}
 */
function cube_shape_to_entity(shape, ecd) {
    const eb = new Entity();

    eb.add(new Transform());
    eb.add(Tag.fromOne(SHAPE_VISUAL_ENTITY_TAG));
    eb.add(ShadedGeometry.from(g_unit_cube, lineMaterial, DrawMode.LineSegments));

    eb.build(ecd);

    return eb;
}


/**
 *
 * @param {UnitSphereShape3D} shape
 * @param {EntityComponentDataset} ecd
 * @returns {Entity}
 */
function sphere_shape_to_entity(shape, ecd) {
    const eb = new Entity();

    eb.add(new Transform());
    eb.add(Tag.fromOne(SHAPE_VISUAL_ENTITY_TAG));
    eb.add(ShadedGeometry.from(g_unit_sphere, lineMaterial, DrawMode.Lines));

    eb.build(ecd);

    return eb;

}

/**
 *
 * @param {TransformedShape3D} shape
 * @param {EntityComponentDataset} ecd
 * @returns {Entity}
 */
function transformed_shape_to_entity(shape, ecd) {
    const subject = shape_to_visual_entity(shape.subject, ecd);

    const parent = new Entity();
    parent
        .add(new Transform())
        .add(AttachmentSockets.fromJSON({
            elements: [
                {
                    type: 0,
                    id: 0
                }
            ]
        }))
        .build(ecd);

    const attachment = Attachment.fromJSON({
        socket: 0,
        parent: parent.id,
        immediate: true
    });

    attachment.transform.fromMatrix(shape.transform);

    subject.add(attachment);

    return parent;
}

/**
 *
 * @param {AbstractShape3D} shape
 * @param {EntityComponentDataset} ecd
 * @returns {Entity}
 */
export function shape_to_visual_entity(shape, ecd) {
    if (shape instanceof UnionShape3D) {
        return composite_shape_to_entity(shape, ecd);
    } else if (shape instanceof UnitCubeShape3D) {
        return cube_shape_to_entity(shape, ecd);
    } else if (shape instanceof SphereShape3D) {
        return sphere_shape_to_entity(shape, ecd);
    } else if (shape instanceof TransformedShape3D) {
        return transformed_shape_to_entity(shape, ecd);
    } else {
        throw new Error('Unsupported shape type');
    }
}
