package day11

import (
	"strconv"
	"strings"
)

func Part1(input string) int {
	stones := ParseInput(input)
	return len(blinkTimes(stones, 25))
}

func Part2(input string) int {
	stones := ParseInput(input)
	return getNumStones(stones, 75)
}

func ParseInput(input string) []int {
	strStones := strings.Split(strings.TrimSpace(input), " ")
	stones := make([]int, 0, len(strStones))
	for _, s := range strStones {
		num, _ := strconv.Atoi(s)
		stones = append(stones, num)
	}
	return stones
}

// Part 1 initial thought of recursion
func blinkTimes(stones []int, times int) []int {
	if times <= 0 {
		return stones
	}
	result := blink(stones)
	return blinkTimes(result, times-1)
}

func blink(stones []int) []int {
	result := make([]int, 0)
	for _, stone := range stones {
		strStone := strconv.Itoa(stone)
		if stone == 0 {
			result = append(result, 1)
		} else if len(strStone)%2 == 0 {
			mid := len(strStone) / 2
			firstHalf, _ := strconv.Atoi(strStone[:mid])
			secondHalf, _ := strconv.Atoi(strStone[mid:])
			result = append(result, firstHalf, secondHalf)
		} else {
			result = append(result, stone*2024)
		}
	}
	return result
}

// Part 2 with maps since blinkTimes(75) would set my computer on fire
func getNumStones(s []int, times int) int {
	stoneMap := make(map[int]int)
	for _, stone := range s {
		stoneMap[stone] = stoneMap[stone] + 1
	}

	for i := 0; i < times; i++ {
		stoneMap2 := make(map[int]int)
		for stone, count := range stoneMap {
			stones := make([]int, 0)
			strStone := strconv.Itoa(stone)
			if stone == 0 {
				stones = append(stones, 1)
			} else if len(strStone)%2 == 0 {
				mid := len(strStone) / 2
				firstHalf, _ := strconv.Atoi(strStone[:mid])
				secondHalf, _ := strconv.Atoi(strStone[mid:])
				stones = append(stones, firstHalf, secondHalf)
			} else {
				stones = append(stones, stone*2024)
			}
			for _, newStone := range stones {
				stoneMap2[newStone] = stoneMap2[newStone] + count
			}
		}
		stoneMap = stoneMap2
	}

	result := 0
	for _, count := range stoneMap {
		result += count
	}
	return result
}
