package main

import (
	"flag"
	"fmt"
	"strconv"
	"strings"

	"github.com/alexchao26/advent-of-code-go/cast"
	"github.com/alexchao26/advent-of-code-go/util"
)

func main() {
	var part int
	flag.IntVar(&part, "part", 1, "part 1 or 2")
	flag.Parse()
	fmt.Println("Running part", part)

	if part == 1 {
		ans := part1(util.ReadFile("./input.txt"))
		fmt.Println("Output:", ans)
	} else {
		ans := part2(util.ReadFile("./input.txt"))
		fmt.Println("Output:", ans)
	}
}

func part1(input string) int {
	recipesWanted := parseInput(input)

	recipes := []int{3, 7}
	elf1, elf2 := 0, 1

	for len(recipes) < recipesWanted+10 {
		recipes, elf1, elf2 = step(recipes, elf1, elf2)
		// fmt.Println("new recipes", recipes)
		// fmt.Println("new elf indices", elf1, elf2)
	}

	ans := 0
	for i := 0; i < 10; i++ {
		ans *= 10
		ans += recipes[i+recipesWanted]
	}

	return ans
}

func part2(input string) int {
	patternToFind := parseInput(input)

	recipes := []int{3, 7}
	elf1, elf2 := 0, 1

	var recipesToLeft int
	for recipesToLeft == 0 {
		recipes, elf1, elf2 = step(recipes, elf1, elf2)

		// check patterns
		recipesToLeft = patternMatch(recipes, patternToFind)
	}

	return recipesToLeft
}

func parseInput(input string) int {
	lines := strings.Split(input, "\n")

	return cast.ToInt(lines[0])
}

func step(recipes []int, elf1, elf2 int) ([]int, int, int) {
	recipe1, recipe2 := recipes[elf1], recipes[elf2]
	newRecipe := recipe1 + recipe2

	// add new recipes onto slice
	if newRecipe >= 10 {
		recipes = append(recipes, 1)
	}
	recipes = append(recipes, newRecipe%10)

	// get new elf indices
	elf1 += recipe1 + 1
	elf2 += recipe2 + 1
	elf1 %= len(recipes)
	elf2 %= len(recipes)

	return recipes, elf1, elf2
}

func patternMatch(recipes []int, patternToFind int) int {
	patternLength := len(strconv.Itoa(patternToFind))
	// not enough recipes to compare
	if len(recipes) < patternLength {
		return 0
	}

	// check last two recipes in recipes slice (because it will grow by at most
	// 2 recipes per step
	var pattern int
	// get first pattern
	for i := len(recipes) - patternLength; i < len(recipes); i++ {
		pattern *= 10
		pattern += recipes[i]
	}

	if pattern == patternToFind {
		return len(recipes) - patternLength
	}

	// check second pattern
	// removes one's digit
	pattern /= 10
	// add new 10^6 digit
	if index := len(recipes) - patternLength - 1; index >= 0 {
		pattern += 100000 * recipes[index]
	}

	if pattern == patternToFind {
		return len(recipes) - patternLength - 1
	}

	// return zero when no pattern is found
	return 0
}
