package main

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

func main() {
	if err := realMain(); err != nil {
		log.Println(err)
	}
}

func realMain() error {
	data, err := parseInput()
	if err != nil {
		return err
	}

	accumulator, _, err := readCode(data)
	if err != nil {
		return err
	}
	log.Println(accumulator)

	accumulator2, err := fixCode(data)
	if err != nil {
		return err
	}
	log.Println(accumulator2)

	return nil
}

func readCode(data []string) (int, int, error) {
	visited := map[int]bool{}
	var acc int
	for i := 0; ; {
		if visited[i] {
			return acc, i, nil
		}
		if i >= len(data) {
			return acc, i, nil
		}
		visited[i] = true
		line := strings.Split(data[i], " ")
		switch line[0] {
		case "nop":
			i++
		case "jmp":
			tmp, err := strconv.Atoi(line[1])
			if err != nil {
				return 0, 0, err
			}
			i += tmp
		case "acc":
			tmp, err := strconv.Atoi(line[1])
			if err != nil {
				return 0, 0, err
			}
			acc += tmp
			i++
		default:
			return 0, 0, fmt.Errorf("unrecognized instruction")
		}
	}
}

func fixCode(data []string) (int, error) {
	for i := range data {
		line := strings.Split(data[i], " ")
		var l string
		switch line[0] {
		case "jmp":
			l = "nop " + line[1]
		case "nop":
			l = "jmp " + line[1]
		default:
			// no change
			continue
		}
		newdata := make([]string, len(data))
		copy(newdata, data)
		newdata[i] = l
		acc, last, err := readCode(newdata)
		if err != nil {
			return 0, err
		}
		if last == len(data) {
			return acc, nil
		}
	}
	return 0, fmt.Errorf("solution not found")
}

func parseInput() ([]string, error) {
	fd, err := os.Open("input.txt")
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	ret := []string{}

	buf := bufio.NewScanner(fd)
	for buf.Scan() {
		ret = append(ret, buf.Text())
	}

	return ret, nil
}