package day07

import (
	"fmt"
	"strconv"
	"strings"
)

func Part1(input string) int {
	total := 0
	lines := strings.Split(strings.TrimSpace(input), "\n")

	for i := 0; i < len(lines); i++ {
		target, numbers := parseLine(lines[i])
		if validLinePart1(numbers, 1, numbers[0], target) {
			total += target
		}
	}

	return total
}

func Part2(input string) int {
	total := 0
	lines := strings.Split(strings.TrimSpace(input), "\n")

	for i := 0; i < len(lines); i++ {
		target, numbers := parseLine(lines[i])
		if validLinePart2(numbers, 1, numbers[0], target) {
			total += target
		}
	}

	return total
}

func parseLine(line string) (int, []int) {
	parts := strings.Split(line, ":")
	target, _ := strconv.Atoi(strings.TrimSpace(parts[0]))
	numberStrings := strings.Fields(parts[1])

	numbers := make([]int, len(numberStrings))
	for i := 0; i < len(numberStrings); i++ {
		numbers[i], _ = strconv.Atoi(strings.TrimSpace(numberStrings[i]))
	}

	return target, numbers
}

func validLinePart1(numbers []int, index int, currentValue int, target int) bool {
	if index == len(numbers) {
		return currentValue == target
	}

	sum := currentValue + numbers[index]
	if validLinePart1(numbers, index+1, sum, target) {
		return true
	}

	product := currentValue * numbers[index]
	if validLinePart1(numbers, index+1, product, target) {
		return true
	}

	return false
}

func validLinePart2(numbers []int, index int, currentValue int, target int) bool {
	if index == len(numbers) {
		return currentValue == target
	}

	sum := currentValue + numbers[index]
	if validLinePart2(numbers, index+1, sum, target) {
		return true
	}

	product := currentValue * numbers[index]
	if validLinePart2(numbers, index+1, product, target) {
		return true
	}

	// Turns 12 || 34 into 1234
	concatenated, _ := strconv.Atoi(strings.TrimSpace(fmt.Sprintf("%d%d", currentValue, numbers[index])))
	if validLinePart2(numbers, index+1, concatenated, target) {
		return true
	}

	return false
}
