package day07

func SimulateConstruction(root *Node) int {
	working := make(map[rune]*Node)
	done := map[rune]bool{
		0: true,
	}
	elapsed := 0

	for {
		// returns true when no work is left to do.
		if tick(root, working, done) {
			return elapsed
		}

		elapsed++
	}
}

func tick(root *Node, working map[rune]*Node, done map[rune]bool) bool {
	complete := true

	// Find candidates, if we need new ones.
	if len(working) < 5 {
		candidates := findCandidates(root, done)
		for _, candidate := range candidates {
			if len(working) >= 5 {
				break
			}

			// if we see a candidate that we can work on, put it in the map.
			if working[candidate.Name] == nil {
				working[candidate.Name] = candidate
				complete = false
			}
		}
	}

	// work on each in-progress node.
	for _, node := range working {
		complete = false
		node.Worked++

		// if we're done, add it to done and delete from worker queue
		// `-4` is exploiting the fact that the rune capital A is value
		// 65 as an integer (and so on)
		if node.Worked >= int(node.Name)-4 {
			done[node.Name] = true
			delete(working, node.Name)
		}
	}

	return complete
}