import { observer } from "mobx-react-lite";
import type { ObjectInstance } from "../types";
import { useEffect, useRef, type RefObject } from "react";
import type { Group } from "three";
import { TransformControls, useHelper } from "@react-three/drei";
import { BoxHelper } from "three";
import type { ThreeEvent } from "@react-three/fiber";
import { state } from "../state";
import { nextSelectionEditMode } from "../state/worldEditorState";
import type { R3 } from "../types/3d";

type ObjectViewProps = {
    object: ObjectInstance;
}

export const ObjectView = observer(function ({ object }: ObjectViewProps) {
    const groupRef = useRef<Group>(null);
    const controlsRef = useRef<any>(null);

    const isSelected = state.worldEditor.isEnabled &&
        state.worldEditor.selectedObjectId === object.id;

    useHelper(isSelected ? groupRef : { current: null } as any, BoxHelper, 'white');

    const objectType = state.world.getObjectTypeById(object.typeId);
    if (!objectType)
        return null;
    const selectionMode = isSelected
        ? state.worldEditor.selectedObjectMode
        : undefined;

    useEffect(() => {
        if (!isSelected)
            return;
        const controls = controlsRef.current;
        if (!controls)
            return;
        const onDragChanged = (e: { value: boolean }) => {
            state.worldEditor.setIsDragging(e.value);
            if (!e.value) {
                const group = groupRef.current;
                if (group)
                    state.worldEditor.setObjectTransform(
                        object.id,
                        group.position.toArray(),
                        group.rotation.toArray().slice(0, 3) as R3,
                        group.scale.toArray(),
                    );
            }
        };
        controls.addEventListener('dragging-changed', onDragChanged);
        return () => {
            controls.removeEventListener('dragging-changed', onDragChanged);
            state.worldEditor.setIsDragging(false);
        };
    }, [isSelected]);

    const handleClick = (e: ThreeEvent<MouseEvent>) => {
        if (!state.worldEditor.isEnabled)
            return;
        if (e.delta > 5)
            return;
        e.stopPropagation();

        state.worldEditor.setSelectedObject(object.id, nextSelectionEditMode(selectionMode));
    };

    return (<>
        {
            (isSelected && (selectionMode !== undefined) && groupRef.current) &&
            <TransformControls
                object={groupRef as RefObject<Group>}
                mode={selectionMode}
            />
        }
        <group
            ref={groupRef}
            position={object.position}
            rotation={object.rotation}
            scale={object.scale}
            onClick={handleClick}
        >
            {
                objectType.voxels.map((v, idx) => {
                    const vt = state.world.getVoxelTypeById(v.typeId);
                    const color = (v.color ?? vt?.color) ?? 'white';
                    const opacity = (v.opacity ?? vt?.opacity) ?? 1;
                    return (
                        <mesh key={idx} position={v.position}>
                            <boxGeometry args={[1, 1, 1]} />
                            <meshStandardMaterial
                                color={color}
                                opacity={opacity}
                                transparent={opacity < 1}
                            />
                        </mesh>
                    );
                })
            }
        </group>
    </>);
});
