import { extractTriggersFromPoint } from "./extractTriggersFromPoint";

export async function determineExecutionSequences(products: productsSchema): Promise<PointsScheme[][]> {
    // Create maps for all points
    const pointMap = new Map<string, PointsScheme>();
    const allPoints: PointsScheme[] = [];

    // First pass: collect all points
    products.forEach(product => {
        product.eventDatas.forEach(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' ||
                event.type === 'roboticArm' ||
                event.type === 'human'
            ) {
                pointMap.set(event.point.uuid, event.point);
                allPoints.push(event.point);
            }
        });
    });

    // Build complete dependency graph
    const dependencyGraph = new Map<string, string[]>();
    const reverseDependencyGraph = new Map<string, string[]>();
    const triggeredPoints = 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);
                triggeredPoints.add(targetUuid);

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

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

    // Identify independent root points (points that trigger others but aren't triggered themselves)
    const rootPoints = allPoints.filter(point => {
        const hasOutgoingTriggers = extractTriggersFromPoint(point).some(
            t => t.triggeredAsset?.triggeredPoint?.pointUuid
        );
        return hasOutgoingTriggers && !triggeredPoints.has(point.uuid);
    });

    // For each root point, build its complete trigger chain
    const executionSequences: PointsScheme[][] = [];

    function buildSequence(startUuid: string): PointsScheme[] {
        const sequence: PointsScheme[] = [];
        const visited = new Set<string>();

        function traverse(uuid: string) {
            if (visited.has(uuid)) return;
            visited.add(uuid);

            const point = pointMap.get(uuid);
            if (point) {
                sequence.push(point);
            }

            // Follow forward dependencies
            const nextPoints = dependencyGraph.get(uuid) || [];
            nextPoints.forEach(nextUuid => traverse(nextUuid));
        }

        traverse(startUuid);
        return sequence;
    }

    // Build sequences for all root points
    rootPoints.forEach(root => {
        executionSequences.push(buildSequence(root.uuid));
    });

    // Handle any triggered points not reachable from roots (isolated chains)
    const processedPoints = new Set(
        executionSequences.flat().map(p => p.uuid)
    );

    allPoints.forEach(point => {
        if (triggeredPoints.has(point.uuid) && !processedPoints.has(point.uuid)) {
            executionSequences.push(buildSequence(point.uuid));
        }
    });

    return executionSequences;
}