package main

import (
	"fmt"
	"strings"

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

func main() {
	inp := h.StdinToStringSlice()
	part1(inp)
	part2(inp)
}

func part1(input []string) {
	allGames := parseAllGames(input)
	var result int
	for i := range allGames {
		if allGames[i].getMost("red") > 12 {
			continue
		}
		if allGames[i].getMost("green") > 13 {
			continue
		}
		if allGames[i].getMost("blue") > 14 {
			continue
		}
		result += allGames[i].id
	}
	fmt.Println("# Part 1")
	fmt.Println(result)
}

func part2(input []string) {
	allGames := parseAllGames(input)
	var result int
	for i := range allGames {
		result += allGames[i].getMinimumPower()
	}
	fmt.Println("# Part 2")
	fmt.Println(result)
}

func parseAllGames(input []string) []Game {
	allGames := []Game{}
	for i := range input {
		gameNo, r := parseGame(input[i])
		allGames = append(allGames, Game{id: gameNo, pulls: r})
	}
	return allGames
}

type Pull struct {
	subsets map[string]int
}

func (p Pull) String() string {
	ret := ""
	for k, v := range p.subsets {
		ret = fmt.Sprintf("%s%d %s, ", ret, v, k)
	}
	return ret
}

type Game struct {
	id    int
	pulls []Pull
}

func (g *Game) getMost(color string) int {
	max := h.MIN_INT
	for i := range g.pulls {
		if v, ok := g.pulls[i].subsets[color]; ok {
			if v > max {
				max = v
			}
		}
	}
	return max
}

func (g *Game) getMinimumPower() int {
	maxRed := g.getMost("red")
	maxBlue := g.getMost("blue")
	maxGreen := g.getMost("green")
	return maxRed * maxBlue * maxGreen
}

func (g Game) String() string {
	ret := fmt.Sprintf("Game %d: ", g.id)
	for i := range g.pulls {
		ret = fmt.Sprintf("%s%s; ", ret, g.pulls[i])
	}
	return ret
}

func parsePulls(input string) Pull {
	ret := Pull{subsets: make(map[string]int)}
	pts := strings.Split(input, ",")
	for i := range pts {
		blocks := strings.Fields(pts[i])
		ret.subsets[blocks[1]] = h.Atoi(blocks[0])
	}
	return ret
}
func parseGame(input string) (int, []Pull) {
	res := []Pull{}
	pts := strings.Split(input, ":")
	gameNo := h.Atoi(strings.Fields(pts[0])[1])
	pulls := strings.Split(pts[1], ";")
	for i := range pulls {
		res = append(res, parsePulls(pulls[i]))
	}

	return gameNo, res
}