import { createContext, useContext, useMemo, useRef } from 'react';

import { createAssetStore, AssetStoreType } from '../../store/builder/useAssetStore';
import { createWallAssetStore, WallAssetStoreType } from '../../store/builder/useWallAssetStore';
import { createWallStore, WallStoreType } from '../../store/builder/useWallStore';
import { createAisleStore, AisleStoreType } from '../../store/builder/useAisleStore';
import { createZoneStore, ZoneStoreType } from '../../store/builder/useZoneStore';
import { createFloorStore, FloorStoreType } from '../../store/builder/useFloorStore';

import { createUndoRedo2DStore, UndoRedo2DStoreType } from '../../store/builder/useUndoRedo2DStore';

import { createEventStore, EventStoreType } from '../../store/simulation/useEventsStore';
import { createProductStore, ProductStoreType } from '../../store/simulation/useProductStore';

import { createMaterialStore, MaterialStoreType } from '../../store/simulation/useMaterialStore';
import { createArmBotStore, ArmBotStoreType } from '../../store/simulation/useArmBotStore';
import { createMachineStore, MachineStoreType } from '../../store/simulation/useMachineStore';
import { createConveyorStore, ConveyorStoreType } from '../../store/simulation/useConveyorStore';
import { createVehicleStore, VehicleStoreType } from '../../store/simulation/useVehicleStore';
import { createStorageUnitStore, StorageUnitStoreType } from '../../store/simulation/useStorageUnitStore';
import { createHumanStore, HumanStoreType } from '../../store/simulation/useHumanStore';
import { createCraneStore, CraneStoreType } from '../../store/simulation/useCraneStore';

type SceneContextValue = {

    assetStore: AssetStoreType,
    wallAssetStore: WallAssetStoreType,
    wallStore: WallStoreType,
    aisleStore: AisleStoreType,
    zoneStore: ZoneStoreType,
    floorStore: FloorStoreType,

    undoRedo2DStore: UndoRedo2DStoreType,

    eventStore: EventStoreType,
    productStore: ProductStoreType,

    materialStore: MaterialStoreType;
    armBotStore: ArmBotStoreType;
    machineStore: MachineStoreType;
    conveyorStore: ConveyorStoreType;
    vehicleStore: VehicleStoreType;
    storageUnitStore: StorageUnitStoreType;
    humanStore: HumanStoreType;
    craneStore: CraneStoreType;

    humanEventManagerRef: React.RefObject<HumanEventManagerState>;

    clearStores: () => void;

    layout: 'Main Layout' | 'Comparison Layout';
};

const SceneContext = createContext<SceneContextValue | null>(null);

export function SceneProvider({
    children,
    layout
}: {
    readonly children: React.ReactNode;
    readonly layout: 'Main Layout' | 'Comparison Layout';
}) {

    const assetStore = useMemo(() => createAssetStore(), []);
    const wallAssetStore = useMemo(() => createWallAssetStore(), []);
    const wallStore = useMemo(() => createWallStore(), []);
    const aisleStore = useMemo(() => createAisleStore(), []);
    const zoneStore = useMemo(() => createZoneStore(), []);
    const floorStore = useMemo(() => createFloorStore(), []);

    const undoRedo2DStore = useMemo(() => createUndoRedo2DStore(), []);

    const eventStore = useMemo(() => createEventStore(), []);
    const productStore = useMemo(() => createProductStore(), []);

    const materialStore = useMemo(() => createMaterialStore(), []);
    const armBotStore = useMemo(() => createArmBotStore(), []);
    const machineStore = useMemo(() => createMachineStore(), []);
    const conveyorStore = useMemo(() => createConveyorStore(), []);
    const vehicleStore = useMemo(() => createVehicleStore(), []);
    const storageUnitStore = useMemo(() => createStorageUnitStore(), []);
    const humanStore = useMemo(() => createHumanStore(), []);
    const craneStore = useMemo(() => createCraneStore(), []);

    const humanEventManagerRef = useRef<HumanEventManagerState>({ humanStates: [] });

    const clearStores = useMemo(() => () => {
        assetStore.getState().clearAssets();
        wallAssetStore.getState().clearWallAssets();
        wallStore.getState().clearWalls();
        aisleStore.getState().clearAisles();
        zoneStore.getState().clearZones();
        floorStore.getState().clearFloors();
        undoRedo2DStore.getState().clearUndoRedo2D();
        eventStore.getState().clearEvents();
        productStore.getState().clearProducts();
        materialStore.getState().clearMaterials();
        armBotStore.getState().clearArmBots();
        machineStore.getState().clearMachines();
        conveyorStore.getState().clearConveyors();
        vehicleStore.getState().clearVehicles();
        storageUnitStore.getState().clearStorageUnits();
        humanStore.getState().clearHumans();
        craneStore.getState().clearCranes();
        humanEventManagerRef.current.humanStates = [];
    }, [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, undoRedo2DStore, floorStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore]);

    const contextValue = useMemo(() => (
        {
            assetStore,
            wallAssetStore,
            wallStore,
            aisleStore,
            zoneStore,
            floorStore,
            undoRedo2DStore,
            eventStore,
            productStore,
            materialStore,
            armBotStore,
            machineStore,
            conveyorStore,
            vehicleStore,
            storageUnitStore,
            humanStore,
            craneStore,
            humanEventManagerRef,
            clearStores,
            layout
        }
    ), [assetStore, wallAssetStore, wallStore, aisleStore, zoneStore, floorStore, undoRedo2DStore, eventStore, productStore, materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, craneStore, clearStores, layout]);

    return (
        <SceneContext.Provider value={contextValue}>
            {children}
        </SceneContext.Provider>
    );
}

// Base hook to get the context
export function useSceneContext() {
    const context = useContext(SceneContext);
    if (!context) {
        throw new Error('useSceneContext must be used within a SceneProvider');
    }
    return context;
}