package main

import (
	"fmt"
	"strings"

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

var template string
var insertions map[string]string

func main() {
	insertions = make(map[string]string)
	inp := h.StdinToStringSlice()
	template = inp[0]
	for i := 2; i < len(inp); i++ {
		pts := strings.Split(inp[i], " -> ")
		insertions[pts[0]] = pts[1]
	}
	part1(template)
	fmt.Println()
	part2(template)
}

func transform(inp string) string {
	var ret string
	for i := 0; i < len(inp)-1; i++ {
		pair := inp[i : i+2]
		ret = ret + string(inp[i]) + insertions[pair]
	}
	ret = ret + string(inp[len(inp)-1])
	return ret
}

func part1(inp string) {
	for i := 0; i < 10; i++ {
		inp = transform(inp)
	}
	countMap := make(map[byte]int)
	for i := range inp {
		countMap[inp[i]]++
	}
	var mostCommon, leastCommon byte
	mostCount := h.MIN_INT
	leastCount := h.MAX_INT
	for k, v := range countMap {
		if v > mostCount {
			mostCount = v
			mostCommon = k
		}
		if v < leastCount {
			leastCount = v
			leastCommon = k
		}
	}
	fmt.Println("# Part 1")
	fmt.Printf("Most Common: %s (%d)\n", string(mostCommon), mostCount)
	fmt.Printf("Least Common: %s (%d)\n", string(leastCommon), leastCount)
	fmt.Println("Answer", (mostCount - leastCount))
}

func part2Transform(pairs map[string]int) map[string]int {
	ret := make(map[string]int)
	for k, v := range pairs {
		add := insertions[k]
		p1, p2 := string(k[0])+add, add+string(k[1])
		ret[p1] += v
		ret[p2] += v
	}
	return ret
}

func part2(inp string) {
	// So the obvious way doesn't work for this many steps.
	// Let's try just dealing with pairs.
	pairs := make(map[string]int)
	for i := 0; i < len(inp)-1; i++ {
		pair := inp[i : i+2]
		pairs[pair]++
	}
	for i := 0; i < 40; i++ {
		pairs = part2Transform(pairs)
	}
	countMap := make(map[byte]int)
	for k, v := range pairs {
		countMap[k[0]] = countMap[k[0]] + v
	}
	countMap[inp[len(inp)-1]]++

	var mostCommon, leastCommon byte
	mostCount := h.MIN_INT
	leastCount := h.MAX_INT
	for k, v := range countMap {
		if v > mostCount {
			mostCount = v
			mostCommon = k
		}
		if v < leastCount {
			leastCount = v
			leastCommon = k
		}
	}
	fmt.Println("# Part 2")
	fmt.Printf("Most Common: %s (%d)\n", string(mostCommon), mostCount)
	fmt.Printf("Least Common: %s (%d)\n", string(leastCommon), leastCount)
	fmt.Println("Answer", (mostCount - leastCount))
}