import { useEffect } from 'react';
import { useProductStore } from '../../../store/simulation/useProductStore';
import { useActionHandler } from '../actions/useActionHandler';

function Simulator() {
    const { products } = useProductStore();
    const { handleAction } = useActionHandler();

    useEffect(() => {
        const executionOrder = determineExecutionOrder(products);
        executionOrder.forEach(point => {
            if ('actions' in point) {
                handleAction(point.actions[0]);
            }else{
                handleAction(point.action);
            }
        });
    }, [products, handleAction]);

    function determineExecutionOrder(products: productsSchema): PointsScheme[] {
        // Create maps for all events and points
        const eventMap = new Map<string, EventsSchema>();
        const pointMap = new Map<string, PointsScheme>();
        const allPoints: PointsScheme[] = [];

        // First pass: collect all points
        products.forEach(product => {
            product.eventDatas.forEach(event => {
                eventMap.set(event.modelUuid, event);

                if (event.type === 'transfer') {
                    event.points.forEach(point => {
                        pointMap.set(point.uuid, point);
                        allPoints.push(point);
                    });
                } else if (event.type === 'vehicle' ||
                    event.type === 'machine' ||
                    event.type === 'storageUnit') {
                    pointMap.set(event.point.uuid, event.point);
                    allPoints.push(event.point);
                } else if (event.type === 'roboticArm') {
                    pointMap.set(event.point.uuid, event.point);
                    allPoints.push(event.point);
                }
            });
        });

        // Build dependency graphs
        const graph = new Map<string, string[]>();
        const reverseGraph = new Map<string, string[]>();
        const allTriggeredPoints = new Set<string>();

        allPoints.forEach(point => {
            const triggers = extractTriggersFromPoint(point);
            const dependencies: string[] = [];

            triggers.forEach(trigger => {
                const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid;
                if (targetUuid && pointMap.has(targetUuid)) {
                    dependencies.push(targetUuid);
                    allTriggeredPoints.add(targetUuid);

                    if (!reverseGraph.has(targetUuid)) {
                        reverseGraph.set(targetUuid, []);
                    }
                    reverseGraph.get(targetUuid)!.push(point.uuid);
                }
            });

            graph.set(point.uuid, dependencies);
        });

        // Identify root points (points that trigger others but aren't triggered themselves)
        const rootPoints = allPoints
            .filter(point => !allTriggeredPoints.has(point.uuid))
            .filter(point => {
                // Only include roots that actually have triggers pointing FROM them
                const triggers = extractTriggersFromPoint(point);
                return triggers.some(t => t.triggeredAsset?.triggeredPoint?.pointUuid);
            });

        // If no root points found but we have triggered points, find the earliest triggers
        if (rootPoints.length === 0 && allTriggeredPoints.size > 0) {
            // This handles cases where we have circular dependencies
            // but still want to include the triggered points
            const minTriggerCount = Math.min(
                ...Array.from(allTriggeredPoints)
                    .map(uuid => (graph.get(uuid) || []).length)
            );
            const potentialRoots = Array.from(allTriggeredPoints)
                .filter(uuid => (graph.get(uuid) || []).length === minTriggerCount);

            rootPoints.push(...potentialRoots.map(uuid => pointMap.get(uuid)!));
        }

        // Topological sort only for triggered points
        const visited = new Set<string>();
        const temp = new Set<string>();
        const order: string[] = [];
        let hasCycle = false;

        function visit(node: string) {
            if (temp.has(node)) {
                hasCycle = true;
                return;
            }
            if (visited.has(node)) return;

            temp.add(node);

            const dependencies = reverseGraph.get(node) || [];
            for (const dep of dependencies) {
                visit(dep);
            }

            temp.delete(node);
            visited.add(node);
            order.push(node);
        }

        // Start processing from root points
        rootPoints.forEach(root => visit(root.uuid));

        // Convert UUIDs back to points and filter out untriggered points
        const triggeredPoints = order
            .map(uuid => pointMap.get(uuid)!)
            .filter(point => allTriggeredPoints.has(point.uuid) ||
                rootPoints.some(root => root.uuid === point.uuid));

        return triggeredPoints;
    }

    function extractTriggersFromPoint(point: PointsScheme): TriggerSchema[] {
        if ('actions' in point) {
            return point.actions.flatMap(action => action.triggers);
        } else if ('action' in point) {
            return point.action.triggers;
        }
        return [];
    }

    return <></>;
}

export default Simulator;