// Importing core classes and types from THREE.js and @react-three/fiber
import * as THREE from "three";
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { DragControls } from 'three/examples/jsm/controls/DragControls';
import { IntersectionEvent } from '@react-three/fiber/dist/declarations/src/core/events';
import { ThreeEvent } from "@react-three/fiber/dist/declarations/src/core/events";
import { RootState } from "@react-three/fiber";
import { CSM } from "three/examples/jsm/csm/CSM";
import { CSMHelper } from 'three/examples/jsm/csm/CSMHelper';
import { CameraControls } from "@react-three/drei";

/** Core THREE.js and React-Fiber Event Types **/

// Event type specific to pointer events in @react-three/fiber
export type ThreeEvent = ThreeEvent<PointerEvent>;


/** Vector and Reference Types **/

// 2D Vector type from THREE.js
export type Vector2 = THREE.Vector2;

// React ref for a mutable 2D vector, useful for tracking changes over time
export type RefVector2 = React.MutableRefObject<THREE.Vector2>;

// 3D Vector type from THREE.js
export type Vector3 = THREE.Vector3;

// Mutable reference for 3D vectors, allowing for dynamic scene changes
export type RefVector3 = React.MutableRefObject<THREE.Vector3 | null>;

// Quaternion type for rotations, using the base structure from THREE.js
export type QuaternionType = THREE.QuaternionLike;


/** Basic Object Types for Scene Management **/

// THREE.js mesh object
export type Mesh = THREE.Mesh;

// Color type allowing various formats (hex, RGB, string, etc.)
export type Color = THREE.Color | string | number;

// Shape type for defining custom geometries
export type Shape = THREE.Shape;

// Event type for intersections within the scene
export type IntersectionEvent = THREE.Intersection;

// Array type for intersections with objects in the scene
export type IntersectsType = THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap>>[];

// Event type for mesh interactions
export type MeshEvent = IntersectionEvent<MouseEvent>;

// Event type for drag interactions
export type DragEvent = DragEvent;

// Generic type for user data attached to objects
export type UserData = any;


/** React Mutable References for Scene Objects **/

// Mutable reference to the scene, used in React-based projects
export type RefScene = React.MutableRefObject<THREE.Scene>;

// THREE.js group type for grouping objects
export type Group = THREE.Group;

// Mutable reference for groups, supporting updates in React components
export type RefGroup = React.MutableRefObject<THREE.Group>;

// Reference type for meshes, allowing null or undefined values
export type RefMesh = React.MutableRefObject<THREE.Mesh | null | undefined>;

// Mutable reference to camera controls
export type RefControls = React.MutableRefObject<CameraControls>;

// Control types for transformation controls in the scene
export type TransformControl = TransformControl;
export type RefTransformControl = React.MutableRefObject<TransformControls>;

// Array of mesh references for tracking multiple meshes
export type RefMeshArray = React.MutableRefObject<THREE.Mesh[]>;

// Array of 3D vectors, useful for handling points or positions
export type Vector3Array = THREE.Vector3[];

// Drag control type, either a valid DragControls instance or null
export type DragControl = DragControls | null;
export type RefDragControl = React.MutableRefObject<DragControls | null>;


/** Primitive Types with Mutable References **/

export type String = string;
export type RefStringArray = React.MutableRefObject<string[]>;
export type RefString = React.MutableRefObject<String | null>;

export type Boolean = boolean;
export type RefBoolean = React.MutableRefObject<Boolean | null>;

export type Number = number;
export type NumberArray = number[];

// Reference for the THREE.js Raycaster, useful in handling ray intersections
export type RefRaycaster = React.MutableRefObject<THREE.Raycaster>;

// Camera reference, supporting both perspective and basic cameras
export type RefCamera = React.MutableRefObject<THREE.Camera | THREE.PerspectiveCamera>;


/** Three.js Root State Management **/

// Root state of the @react-three/fiber instance, providing context of the scene
export type ThreeState = RootState;


/** Point and Line Types for Spatial Geometry **/

// Defines a point in 3D space with metadata for unique identification
export type Point = [THREE.Vector3, string, number, string];

// Defines a line as two connected points, commonly used in scene building
export type Line = [Point, Point];

// Reference for a line, allowing dynamic updates
export type RefLine = React.MutableRefObject<Line | [Point] | []>;

// Collection of lines for structured geometry
export type Lines = Array<Line>;


/** Wall and Room Types for 3D Space Management **/

// Defines a wall with its geometry, position, rotation, material, and layer information
export type Wall = [THREE.ExtrudeGeometry, [number, number, number], [number, number, number], string, number];

// Collection of walls, useful in scene construction
export type Walls = Array<Wall>;

// Reference type for walls, allowing dynamic updates in React
export type RefWalls = React.MutableRefObject<Walls>;

// Room type, containing coordinates and layer metadata for spatial management
export type Rooms = Array<{ coordinates: Array<{ position: THREE.Vector3, uuid: string }>, layer: number }>;

// Reference for room objects, enabling updates within React components
export type RefRooms = React.MutableRefObject<Array<{ coordinates: Array<{ position: THREE.Vector3, uuid: string }>, layer: number }>>;

// Reference for lines, supporting React-based state changes
export type RefLines = React.MutableRefObject<Lines>;


/** Floor Line Types for Layered Structures **/

// Floor line type for single lines on the floor level
export type OnlyFloorLine = Array<Line>;

// Reference for floor lines, allowing manipulation in React
export type RefOnlyFloorLine = React.MutableRefObject<OnlyFloorLine>;

// Collection of lines across multiple floors, for multi-level structures
export type OnlyFloorLines = Array<Lines>;

// Reference for multi-level floor lines, allowing structured updates
export type RefOnlyFloorLines = React.MutableRefObject<OnlyFloorLines>;


/** GeoJSON Line Integration **/

// Structure for representing GeoJSON lines, integrating external data sources
export type GeoJsonLine = {
    line: any;
    uuids: [string, string];
    layer: number;
    type: string;
};


/** State Management Types for React Components **/

// Dispatch types for number and boolean states, commonly used in React hooks
export type NumberIncrementState = React.Dispatch<React.SetStateAction<number>>;
export type BooleanState = React.Dispatch<React.SetStateAction<boolean>>;

// Mutable reference for TubeGeometry, allowing dynamic geometry updates
export type RefTubeGeometry = React.MutableRefObject<THREE.TubeGeometry | null>;


/** Floor Item Configuration **/

// Type for individual items placed on the floor, with positioning and rotation metadata
export type FloorItemType = {
    modeluuid: string;
    modelname: string;
    position: [number, number, number];
    rotation: { x: number; y: number; z: number };
    modelfileID: string;
    isLocked: boolean;
    isVisible: boolean;
};

// Array of floor items for managing multiple objects on the floor
export type FloorItems = Array<FloorItemType>;

// Dispatch type for setting floor item state in React
export type setFloorItemSetState = React.Dispatch<React.SetStateAction<FloorItems | null | undefined>>;


/** Asset Configuration for Loading and Positioning **/

// Configuration for assets, allowing model URLs, scaling, positioning, and types
interface AssetConfiguration {
    modelUrl: string;
    scale?: [number, number, number];
    csgscale?: [number, number, number];
    csgposition?: [number, number, number];
    positionY?: (intersectionPoint: { point: THREE.Vector3 }) => number;
    type?: "Fixed-Move" | "Free-Move";
}

// Collection of asset configurations, keyed by unique identifiers
export type AssetConfigurations = {
    [key: string]: AssetConfiguration;
};


/** Wall Item Configuration **/

// Configuration for wall items, including model, scale, position, and rotation
interface WallItem {
    type: "Fixed-Move" | "Free-Move" | undefined;
    model?: THREE.Group;
    modeluuid?: string
    modelname?: string;
    scale?: [number, number, number];
    csgscale?: [number, number, number];
    csgposition?: [number, number, number];
    position?: [number, number, number];
    quaternion?: Types.QuaternionType;
}

// Collection of wall items, allowing for multiple items in a scene
export type wallItems = Array<WallItem>;

// Dispatch for setting wall item state in React
export type setWallItemSetState = React.Dispatch<React.SetStateAction<WallItem[]>>;

// Dispatch for setting vector3 state in React
export type setVector3State = React.Dispatch<React.SetStateAction<THREE.Vector3>>;

// Dispatch for setting euler state in React
export type setEulerState = React.Dispatch<React.SetStateAction<THREE.Euler>>;

// Reference type for wall items, allowing direct access to the mutable array
export type RefWallItems = React.MutableRefObject<WallItem[]>;


/** Wall and Item Selection State Management **/

// State management for selecting, removing, and indexing wall items
export type setRemoveLayerSetState = (layer: number | null) => void;
export type setSelectedWallItemSetState = (item: THREE.Object3D | null) => void;
export type setSelectedFloorItemSetState = (item: THREE.Object3D | null) => void;
export type setSelectedItemsIndexSetState = (index: number | null) => void;

export type RefCSM = React.MutableRefObject<CSM>;
export type RefCSMHelper = React.MutableRefObject<CSMHelper>;

interface PathConnection {
    fromModelUUID: string;
    fromUUID: string;
    toConnections: {
        toModelUUID: string;
        toUUID: string;
    }[];
}

interface ConnectionStore {
    connections: PathConnection[];
    setConnections: (connections: PathConnection[]) => void;
    addConnection: (newConnection: PathConnection) => void;
    removeConnection: (fromUUID: string, toUUID: string) => void;
}

interface ConveyorEventsSchema {
    modeluuid: string;
    modelName: string;
    type: 'Conveyor';
    points: {
        uuid: string;
        position: [number, number, number];
        rotation: [number, number, number];
        actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
        triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
        connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
    }[];
    position: [number, number, number];
    rotation: [number, number, number];
    speed: number | string;
}

interface VehicleEventsSchema {
    modeluuid: string;
    modelName: string;
    type: 'Vehicle';
    points: {
        uuid: string;
        position: [number, number, number];
        actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
        connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
        speed: number;
    };
    position: [number, number, number];
}

interface StaticMachineEventsSchema {
    modeluuid: string;
    modelName: string;
    type: 'StaticMachine';
    points: {
        uuid: string;
        position: [number, number, number];
        actions: { uuid: string; name: string; buffer: number | string; material: string; isUsed: boolean };
        triggers: { uuid: string; name: string; type: string };
        connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
    };
    position: [number, number, number];
    rotation: [number, number, number];
}

interface ArmBotEventsSchema {
    modeluuid: string;
    modelName: string;
    type: 'ArmBot';
    points: {
        uuid: string;
        position: [number, number, number];
        actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] };
        triggers: { uuid: string; name: string; type: string };
        connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
    };
    position: [number, number, number];
    rotation: [number, number, number];
}

export type EventData = {
    modeluuid: string;
    modelname: string;
    position: [number, number, number];
    rotation: { x: number; y: number; z: number };
    modelfileID: string;
    isLocked: boolean;
    isVisible: boolean;
    eventData?: {
        type: 'Conveyor';
        points: {
            uuid: string;
            position: [number, number, number];
            rotation: [number, number, number];
            actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | [];
            triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number }[] | [];
            connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
        }[];
        speed: number | string;
    } | {
        type: 'Vehicle';
        points: {
            uuid: string;
            position: [number, number, number];
            actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number };
            connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] };
            speed: number;
        };
    };
}
