import { extractTriggersFromPoint } from "./extractTriggersFromPoint";

// Gets all conveyor sequences split by non-transfer events
export function getConveyorSequencesInProduct(
    product: {
        productName: string;
        productUuid: string;
        eventDatas: EventsSchema[];
    }
): EventsSchema[][][] {
    const machineSequences = determineExecutionMachineSequences([product]);
    const allConveyorSequences: EventsSchema[][][] = [];

    for (const machineSequence of machineSequences) {
        const conveyorSequencesForMachine: EventsSchema[][] = [];
        let currentSequence: EventsSchema[] = [];

        for (const event of machineSequence) {
            if (event.type === 'transfer') {
                currentSequence.push(event);
            } else {
                // Split sequence when non-transfer event is encountered
                if (currentSequence.length > 0) {
                    conveyorSequencesForMachine.push([...currentSequence]);
                    currentSequence = [];
                }
            }
        }

        // Add the last sequence if it exists
        if (currentSequence.length > 0) {
            conveyorSequencesForMachine.push([...currentSequence]);
        }

        if (conveyorSequencesForMachine.length > 0) {
            allConveyorSequences.push(conveyorSequencesForMachine);
        }
    }

    return allConveyorSequences;
}

// Finds the subsequence containing a specific conveyor
export function findConveyorSubsequence(
    product: {
        productName: string;
        productUuid: string;
        eventDatas: EventsSchema[];
    },
    conveyorModelUuid: string
): {
    allSequences: EventsSchema[][][];
    parentSequence: EventsSchema[][];
    currentSubSequence: EventsSchema[];
} | null {
    const allSequences = getConveyorSequencesInProduct(product);

    for (const parentSequence of allSequences) {
        for (const currentSubSequence of parentSequence) {
            const hasTargetConveyor = currentSubSequence.some(
                event => event.type === 'transfer' && event.modelUuid === conveyorModelUuid
            );

            if (hasTargetConveyor) {
                return {
                    allSequences,
                    parentSequence,
                    currentSubSequence
                };
            }
        }
    }

    return null;
}

// Helper function to get machine sequences (simplified from your example)
function determineExecutionMachineSequences(products: productsSchema): EventsSchema[][] {
    const pointToEventMap = new Map<string, EventsSchema>();
    const allPoints: PointsScheme[] = [];

    // First pass: map points to their corresponding events
    products.forEach(product => {
        product.eventDatas.forEach(event => {
            if (event.type === 'transfer') {
                event.points.forEach(point => {
                    pointToEventMap.set(point.uuid, event);
                    allPoints.push(point);
                });
            } else if (
                event.type === 'vehicle' ||
                event.type === 'machine' ||
                event.type === 'storageUnit' ||
                event.type === 'roboticArm' ||
                event.type === 'human' ||
                event.type === 'crane'
            ) {
                pointToEventMap.set(event.point.uuid, event);
                allPoints.push(event.point);
            }
        });
    });

    // Build dependency graph
    const dependencyGraph = 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 && pointToEventMap.has(targetUuid)) {
                dependencies.push(targetUuid);
                triggeredPoints.add(targetUuid);
            }
        });

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

    // Find root points (points that aren't triggered by others)
    const rootPoints = allPoints.filter(point =>
        !triggeredPoints.has(point.uuid) &&
        dependencyGraph.get(point.uuid)?.length
    );

    const executionSequences: EventsSchema[][] = [];

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

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

            const event = pointToEventMap.get(uuid);
            if (event && !sequence.includes(event)) {
                sequence.push(event);
            }

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

        traverse(startUuid);
        return sequence;
    }

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

    return executionSequences;
}