package main

import (
	"fmt"
	"os"
	"strings"
)

func main() {
	content, err := os.ReadFile("data.txt")
	if err != nil {
		panic(err)
	}

	fmt.Println(part1("xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"))
	fmt.Println(part1(string(content)))

	fmt.Println(part2("xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"))
	fmt.Println(part2(string(content)))
}

func part1(s string) (result int) {
	for {
		index := strings.Index(s, "mul(")
		if index < 0 {
			return
		}

		s = s[index+4:]
		op1, opLength := parseOperand(&s)
		if opLength < 1 || opLength > 3 {
			continue
		}

		if !expectChar(&s, ',') {
			continue
		}

		op2, opLength := parseOperand(&s)
		if opLength < 1 || opLength > 3 {
			continue
		}

		if !expectChar(&s, ')') {
			continue
		}

		result += op1 * op2
	}
}

func part2(s string) (result int) {
	for {
		dont_index := strings.Index(s, "don't()")
		if dont_index < 0 {
			result += part1(s)
			return
		}

		result += part1(s[:dont_index])
		s = s[dont_index+7:]

		do_index := strings.Index(s, "do()")
		if do_index < 0 {
			return
		}

		s = s[do_index+4:]
	}

	return
}

func expectChar(s *string, r byte) bool {
	if len(*s) == 0 || (*s)[0] != r {
		return false
	} else {
		*s = (*s)[1:]
		return true
	}
}

func parseOperand(s *string) (operand int, length int) {
	for len(*s) > 0 {
		c := (*s)[0]

		if c < '0' || c > '9' {
			return
		}

		operand = operand*10 + int(c-'0')
		*s = (*s)[1:]
		length++
	}

	return
}