package com.correx.core.transitions.state

import com.correx.core.events.types.StageId
import com.correx.core.transitions.analysis.DetectedCycle
import com.correx.core.transitions.graph.TransitionEdge

internal class CycleDfs {
    fun dfs(
        node: StageId,
        adjacency: Map<StageId, List<TransitionEdge>>,
        state: MutableMap<StageId, VisitState>,
        path: MutableList<StageId>,
        cycles: MutableList<DetectedCycle>
    ) {
        state[node] = VisitState.VISITING
        path.add(node)

        val edges = adjacency[node].orEmpty()

        for (edge in edges) {
            val next = edge.to
            when (state[next]) {
                VisitState.VISITING -> {
                    val cycleStart = path.indexOf(next)
                    if (cycleStart >= 0) {
                        val cycleNodes = path.subList(cycleStart, path.size) + next
                        val cycleEdges = cycleNodes.zipWithNext { from, to ->
                            adjacency[from]?.firstOrNull { it.to == to }
                        }.filterNotNull()
                        cycles.add(DetectedCycle(nodes = cycleNodes, edges = cycleEdges))
                    }
                }

                VisitState.VISITED -> Unit
                null -> dfs(next, adjacency, state, path, cycles)
            }
        }
        path.removeAt(path.lastIndex)
        state[node] = VisitState.VISITED
    }
}
