package day07

import (
	"strings"

	"adventofcode2022/utils"
)

type dir struct {
	name   string
	files  map[string]int
	subdir map[string]*dir
	parent *dir
	size   int
}

func Part1(input string) int {
	root := dir{name: "/", files: map[string]int{}, subdir: map[string]*dir{}, parent: nil}
	root.parse(input)
	sum := 0
	find_dirs_part1(&root, 100000, &sum)
	return sum
}

func Part2(input string) int {
	root := dir{name: "/", files: map[string]int{}, subdir: map[string]*dir{}, parent: nil}
	root.parse(input)
	unused := 70000000 - root.size
	need := 30000000 - unused
	dir_size := 0
	find_dirs_part2(&root, need, &dir_size)
	return dir_size
}

func find_dirs_part1(d *dir, size int, sum *int) {
	// recurse into subdir
	for _, subdir := range d.subdir {
		if (subdir.size) <= size {
			*sum += subdir.size
		}
		find_dirs_part1(subdir, size, sum)
	}
}

func find_dirs_part2(d *dir, size int, sum *int) {
	// recurse into subdir
	for _, subdir := range d.subdir {
		if (subdir.size) >= size && (*sum == 0 || (subdir.size) < *sum) {
			*sum = subdir.size
		}
		find_dirs_part2(subdir, size, sum)
	}
}

func (root *dir) parse(input string) {
	c := root

	for _, line := range strings.Split(input, "\n") {
		pieces := strings.Split(line, " ")
		if pieces[0] == "$" {
			if pieces[1] == "cd" {
				if pieces[2] == ".." {
					c = c.parent
				} else if pieces[2] == "/" {
					c = root
				} else {
					c = c.addDirectoryIfMissing(pieces[2])
				}
			} else if pieces[1] == "ls" {
				// no need to do anything
			} else {
				panic("oops")
			}
		} else if pieces[0] == "dir" {
			c.addDirectoryIfMissing(pieces[1])
		} else {
			c.addFileIfMissing(pieces[1], utils.MustAtoi(pieces[0]))
		}
	}
}

func (d *dir) addDirectoryIfMissing(name string) *dir {
	t, ok := d.subdir[name]
	if !ok {
		t = &dir{
			name:   name,
			files:  map[string]int{},
			subdir: map[string]*dir{},
			parent: d,
		}
		d.subdir[name] = t
	}
	return t
}

func (d *dir) addFileIfMissing(name string, size int) {
	t, ok := d.files[name]
	if ok {
		if t != size {
			panic("oops")
		}
	} else {
		current := d
		d.files[name] = size
		
		for current.name != "/" {
			current.size += size
			current = current.parent
		}
		current.size += size
	}
}