package day07

import (
	"regexp"
	"sort"
)

type Node struct {
	Name     rune
	Parents  []*Node
	Children []*Node
	Worked   int // the amount of time spent working on this node.
}

// BuildDependencyTree parses the input and returns the root node.
func BuildDependencyTree(data []string) *Node {
	depMap := make(map[rune]*Node)
	parentRegex := regexp.MustCompile("Step ([A-Z]) must")
	childRegex := regexp.MustCompile("step ([A-Z]) can begin")

	for _, line := range data {
		parent := rune(parentRegex.FindSubmatch([]byte(line))[1][0])
		child := rune(childRegex.FindSubmatch([]byte(line))[1][0])

		// Create the nodes if they don't exist
		if depMap[parent] == nil {
			depMap[parent] = &Node{Name: parent}
		}
		if depMap[child] == nil {
			depMap[child] = &Node{Name: child}
		}

		// Get each node and add the dependency info.
		pNode := depMap[parent]
		cNode := depMap[child]

		pNode.Children = append(pNode.Children, cNode)
		cNode.Parents = append(cNode.Parents, pNode)
	}

	// sort the children in each node
	for _, node := range depMap {
		sortNodes(node.Children)
	}

	return BuildTreeRoot(depMap)
}

func sortNodes(nodes []*Node) {
	sort.Slice(nodes[:], func(i, j int) bool {
		return nodes[i].Name < nodes[j].Name
	})
}

func BuildTreeRoot(depMap map[rune]*Node) *Node {
	root := &Node{Name: 0}

	for _, node := range depMap {
		if len(node.Parents) == 0 {
			root.Children = append(root.Children, node)
			node.Parents = append(node.Parents, root)
		}
	}

	sortNodes(root.Children)
	return root
}