package main

import (
	"fmt"
	"strings"

	h "git.bullercodeworks.com/brian/adventofcode/helpers"
)

func main() {
	fmt.Println("# Day 7")
	inp := h.StdinToStringSlice()

	allBags := make(map[string]*Bag)
	for _, v := range inp {
		b := ParseBag(v)
		allBags[b.Color] = b
	}
	// Now fill in all 'contains'
	for _, v := range allBags {
		for _, cc := range v.ContainsColors {
			v.Contains = append(v.Contains, allBags[cc])
		}
	}
	whatIGot := "shiny gold"
	var bagsCanContain int
	for _, v := range allBags {
		if v.CanContain(whatIGot) {
			bagsCanContain++
		}
	}
	fmt.Println("## Part 1")
	fmt.Printf("My %s bag can be held by %d bags\n\n", whatIGot, bagsCanContain)
	fmt.Println("## Part 2")
	fmt.Printf("And my bag must contain %d other bags\n", allBags[whatIGot].CountBagsInside())
}

type Bag struct {
	Color          string
	ContainsColors []string
	Contains       []*Bag
}

func ParseBag(inp string) *Bag {
	ret := Bag{}
	pts := strings.Split(inp, " bags contain ")
	ret.Color = pts[0]
	pts[1] = strings.ReplaceAll(pts[1], "bags", "")
	pts[1] = strings.ReplaceAll(pts[1], "bag", "")
	pts[1] = pts[1][:len(pts[1])-2]
	nest := strings.Split(pts[1], ", ")
	for _, v := range nest {
		space := strings.Index(v, " ")
		num, rest := v[:space], strings.TrimSpace(v[space:])
		if num != "no" {
			count := h.Atoi(num)
			for count > 0 {
				ret.ContainsColors = append(ret.ContainsColors, rest)
				count--
			}
		}
	}
	return &ret
}

func (b *Bag) CanContain(color string) bool {
	for _, v := range b.ContainsColors {
		if v == color {
			return true
		}
	}
	for _, v := range b.Contains {
		if v.CanContain(color) {
			return true
		}
	}
	return false
}

func (b *Bag) CountBagsInside() int {
	ret := len(b.Contains)
	for _, v := range b.Contains {
		ret = ret + v.CountBagsInside()
	}
	return ret
}
