package main

import (
	"fmt"
	"strings"

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

func main() {
	inp := h.StdinToString()
	part1(inp)
	fmt.Println()
	part2(inp)
}

func part1(input string) {
	var res int
	pts := strings.Split(input, ",")
	for i := range pts {
		res += hash(pts[i])
	}
	fmt.Println("# Part 1")
	fmt.Println(res)
}

func part2(input string) {
	var boxes []*Box
	for i := 1; i <= 256; i++ {
		boxes = append(boxes, &Box{num: i})
	}
	for _, v := range strings.Split(input, ",") {
		l := NewLens(v)
		if l.focalLength == -1 {
			// Remove
			boxes[l.box].Remove(l)
		} else {
			// Add/Replace
			boxes[l.box].Add(l)
		}
	}
	var res int
	for i := range boxes {
		res += boxes[i].FocusingPower()
	}
	fmt.Println("# Part 2")
	fmt.Println(res)
}

type Box struct {
	num    int
	lenses []*Lens
}

func (b *Box) Add(l *Lens) {
	for i := range b.lenses {
		if b.lenses[i].label == l.label {
			b.lenses[i] = l
			return
		}
	}
	b.lenses = append(b.lenses, l)
}
func (b *Box) Remove(l *Lens) {
	for i := range b.lenses {
		if b.lenses[i].label == l.label {
			b.lenses = append(b.lenses[:i], b.lenses[i+1:]...)
			return
		}
	}
}
func (b *Box) FocusingPower() int {
	var res int
	for i := range b.lenses {
		var lensRes int
		lensRes = b.num
		lensRes *= i + 1
		lensRes *= b.lenses[i].focalLength
		res += lensRes
	}
	return res
}

type Lens struct {
	label       string
	focalLength int
	box         int
}

func NewLens(inp string) *Lens {
	if strings.Contains(inp, "=") {
		pts := strings.Split(inp, "=")
		return &Lens{
			label:       pts[0],
			focalLength: h.Atoi(pts[1]),
			box:         hash(pts[0]),
		}
	} else {
		lbl := strings.TrimSuffix(inp, "-")
		return &Lens{
			label:       lbl,
			focalLength: -1,
			box:         hash(lbl),
		}
	}
}

func hash(inp string) int {
	var res int
	for _, i := range inp {
		res += int(i)
		res *= 17
		res = res % 256
	}
	return res
}

func focusingPower(lens string, boxNum int, boxes [][]string) int {
	res := boxNum + 1
	for i := 1; i <= len(boxes[boxNum]); i++ {
		if boxes[boxNum][i-1] == lens {
			res *= i
			break
		}
	}

	return res
}