package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func digitsToString(input []int) string {
	var str string
	for i := range input {
		str += fmt.Sprintf("%d", input[i])
	}
	return str
}

func digitsToInt(input []int) int {
	var result int
	tens := 1000000
	for i := range input {
		result += input[i] * tens
		tens /= 10
	}
	return result
}

func getPattern(phase int) []int {
	base := []int{0, 1, 0, -1}

	pattern := make([]int, 0)
	for i := range base {
		for j := 0; j < phase; j++ {
			pattern = append(pattern, base[i])
		}
	}
	return pattern
}

func phase(input []int, debug bool) []int {
	result := make([]int, len(input))
	for i := range input {
		pattern := getPattern(i + 1)
		p := 1
		for j := range input {
			var prefix string
			if j > 0 {
				prefix = " + "
			}
			result[i] += input[j] * pattern[p]
			if debug {
				fmt.Printf("%s%d*%2d", prefix, input[j], pattern[p])
			}
			p = (p + 1) % len(pattern)
		}
		if result[i] < 0 {
			result[i] = -result[i]
		}
		if result[i] > 9 {
			result[i] %= 10
		}
		if debug {
			fmt.Printf(" = %d\n", result[i])
		}
	}
	return result
}

func FFT(input []int, phases int, debug bool) []int {
	result := make([]int, len(input))
	copy(result, input)

	if debug {
		fmt.Printf("Input signal: %s\n\n", digitsToString(input))
	}
	var current int
	for current < phases {
		current++
		result = phase(result, debug)
		if debug {
			fmt.Printf("\nAfter %d phase: %s\n\n", current, digitsToString(result))
		}
	}

	return result
}

func FFT2(input []int, phases, offset int, debug bool) []int {
	length := (len(input) * 10000) - offset
	result := make([]int, length)

	step := offset
	for i := 0; i < length; i++ {
		result[i] = input[step%len(input)]
		step++
	}

	if debug {
		fmt.Printf("Input signal: %s\n\n", digitsToString(input))
	}
	var current int
	for current < phases {
		current++

		for i := length - 2; i >= 0; i-- {
			result[i] = (result[i] + result[i+1]) % 10
		}

		if debug {
			fmt.Printf("\nAfter %d phase: %s\n\n", current, digitsToString(result))
		}
	}

	return result
}

func main() {
	input, err := os.Open("input.txt")
	if err != nil {
		log.Fatal(fmt.Errorf("could not open input file: %w", err))
	}
	defer input.Close()

	scanner := bufio.NewScanner(input)

	digits := make([]int, 0)
	for scanner.Scan() {
		r := scanner.Bytes()
		for i := range r {
			digits = append(digits, int(r[i]-48))
		}
	}

	p1 := FFT(digits, 100, false)
	p2 := FFT2(digits, 100, digitsToInt(digits[:7]), false)
	fmt.Printf("Part 1: %s\n", digitsToString(p1[:8]))
	fmt.Printf("Part 2: %s\n", digitsToString(p2[:8]))
}