package day22

import (
	"adventofcode2024/utils"
	rb "adventofcode2024/utils/ringbuffer"
	"strconv"
	"strings"
)

func Part1(input string) int {
	var secret uint
	total := 0
	secrets := strings.Split(input, "\n")
	for _, secret_str := range secrets {
		secret = uint(utils.MustAtoi(secret_str))
		for i := 0; i < 2000; i++ {
			secret ^= secret * 64
			secret %= 16777216
			secret ^= secret / 32
			secret %= 16777216
			secret ^= secret * 2048
			secret %= 16777216
		}
		total += int(secret)
	}
	return total
}

func Part2(input string) int {
	var secret uint
	var banannas0, banannas1, banannas2, banannas3, banannas4 int
	seq_map := make(map[string]int)
	total := 0
	ringBuffer := rb.NewRingBuffer[uint](5)

	secrets := strings.Split(input, "\n")
	for _, secret_str := range secrets {
		found_map := make(map[string]bool)
		secret = uint(utils.MustAtoi(secret_str))
		for i := 0; i < 2000; i++ {
			secret = get_next_secret(secret)
			ringBuffer.Add(secret)
			if ringBuffer.Len() < 5 { continue }
			ring := ringBuffer.Get()
			banannas0 = get_bannnas(ring[0])
			banannas1 = get_bannnas(ring[1])
			banannas2 = get_bannnas(ring[2])
			banannas3 = get_bannnas(ring[3])
			banannas4 = get_bannnas(ring[4])
			map_str := diff_bannanas(banannas1, banannas0) +
				diff_bannanas(banannas2, banannas1) +
				diff_bannanas(banannas3, banannas2) +
				diff_bannanas(banannas4, banannas3)
			if _, ok := found_map[map_str]; !ok {
				seq_map[map_str] += banannas4
				found_map[map_str] = true
			}
		}
	}
	for _, v := range seq_map {
		if v > total {
			total = v
		}
	}
	return total
}

func get_next_secret(in uint) uint {
	in ^= in * 64
	in %= 16777216
	in ^= in / 32
	in %= 16777216
	in ^= in * 2048
	in %= 16777216
	return in
}

func get_bannnas(secret uint) int {
	return int(secret) % 10
}

func diff_bannanas(a, b int) string {
	ret := ""
	diff := a - b
	if diff >= 0 {
		ret = "+" + strconv.Itoa(diff)
	} else {
		ret = strconv.Itoa(diff)
	}
	return ret
}
