package main

import (
	"fmt"

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

func main() {
	inp := h.StdinToStringSlice()
	m := h.StringSliceToCoordByteMap(inp)

	findBasins(m, findLowestPoints(m))
}

func findLowestPoints(m h.CoordByteMap) []h.Coordinate {
	var points []h.Coordinate
	var low []int
	for y := 0; y < m.Height; y++ {
		for x := 0; x < m.Width; x++ {
			c := h.Coordinate{X: x, Y: y}
			v := m.Get(c)
			if y > 0 { // Check North
				if m.Get(c.North()) <= v {
					continue
				}
			}
			if y < m.Height-1 { // Check South
				if m.Get(c.South()) <= v {
					continue
				}
			}
			if x > 0 { // Check West
				if m.Get(c.West()) <= v {
					continue
				}
			}
			if x < m.Width-1 { // Check East
				if m.Get(c.East()) <= v {
					continue
				}
			}
			points = append(points, c)
			low = append(low, btoi(v))
		}
	}
	fmt.Println()
	fmt.Println("# Part 1")
	var tot int
	for i := range low {
		tot += low[i] + 1
	}
	fmt.Println("Total Risk Level:", tot)
	return points
}

func findBasins(m h.CoordByteMap, lows []h.Coordinate) {
	basins := make(map[h.Coordinate]int)
	for i := range lows {
		basins[lows[i]], _ = findBasinSize(m, lows[i], make(map[h.Coordinate]bool))
	}
	// Find the three largest
	one := h.MIN_INT
	two := h.MIN_INT
	three := h.MIN_INT
	for _, v := range basins {
		if v > one {
			one, two, three = v, one, two
		} else if v > two {
			two, three = v, two
		} else if v > three {
			three = v
		}
	}
	fmt.Println()
	fmt.Println("# Part 2")
	fmt.Println("Total:", (one * two * three))
}

func findBasinSize(m h.CoordByteMap, low h.Coordinate, checked map[h.Coordinate]bool) (int, map[h.Coordinate]bool) {
	size := 1
	checked[low] = true
	for _, v := range []h.Coordinate{low.North(), low.East(), low.South(), low.West()} {
		if m.Get(v) != 0 && !checked[v] && btoi(m.Get(v)) < 9 {
			var s int
			s, checked = findBasinSize(m, v, checked)
			size += s
		}
	}

	return size, checked
}

func btoi(b byte) int {
	return int(b) - 48
}
