package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

type Bag struct {
	count int64
	name  string
}

func getBags(line string, bags map[string][]Bag) {
	bugNameRegex := regexp.MustCompile(`(\w+\s\w+) bags contain `)
	result := bugNameRegex.FindStringSubmatch(line)
	if len(result) != 2 {
		return
	}

	bagName := result[1]

	bugContainsRegex := regexp.MustCompile(`(\d+)\s(\w+\s\w+)`)
	subStrings := strings.Split(line, ", ")
	for _, sub := range subStrings {
		subResult := bugContainsRegex.FindStringSubmatch(sub)
		if len(subResult) != 3 {
			continue
		}

		number, err := strconv.ParseInt(subResult[1], 10, 32)
		if err != nil {
			continue
		}

		bags[bagName] = append(bags[bagName], Bag{name: subResult[2], count: number})
	}
}

func readFile(filePath string, bags map[string][]Bag) {
	file, err := os.Open(filePath)
	if err != nil {
		log.Fatalf("failed to open")

	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		getBags(line, bags)
	}
	if err := scanner.Err(); err != nil {
		log.Println(err)
	}
}

func checkBag(phrase string, bagName string, bags map[string][]Bag) bool {
	for _, bag := range bags[bagName] {
		if bag.name == phrase {
			return true
		}

		if checkBag(phrase, bag.name, bags) {
			return true
		}
	}

	return false
}

func countBagsContaining(phrase string, bags map[string][]Bag) int {
	count := 0

	for name, _ := range bags {
		if name == phrase {
			continue
		}

		if checkBag(phrase, name, bags) {
			count++
		}
	}

	return count
}

func countBagsIn(bag string, bags map[string][]Bag) int64 {
	var count int64 = 0

	for _, value := range bags[bag] {
		count += value.count

		count += value.count * countBagsIn(value.name, bags)
	}

	return count
}

func main() {
	if len(os.Args) < 2 {
		log.Fatal("You need to specify a file!")
	}

	var bags = make(map[string][]Bag)

	readFile(os.Args[1], bags)
	fmt.Println("Part1:", countBagsContaining("shiny gold", bags))
	fmt.Println("Part2:", countBagsIn("shiny gold", bags))
}