package main

import (
	"AOC2021/src/helper"
	"fmt"
	"os"
	"strings"
	"unicode"
)

func main() {
	args := os.Args[1:]
	input, err := helper.GetInput(args[0])
	if err != nil {
		fmt.Println(err)
	}

	routeMap := make(map[string][]string)
	for _, line := range input {
		splitLine := strings.Split(line, "-")
		if splitLine[0] != "start" && splitLine[1] != "end" {
			routeMap[splitLine[1]] = append(routeMap[splitLine[1]], splitLine[0])
		}
		if splitLine[1] != "start" && splitLine[0] != "end" {
			routeMap[splitLine[0]] = append(routeMap[splitLine[0]], splitLine[1])
		}
	}
	for key, val := range routeMap {
		fmt.Printf("%s : %s \n", key, val)
	}

	//part1
	allRoutesCounter := 0
	getRoute(&routeMap, []string{"start"}, &allRoutesCounter, 1)
	fmt.Println(allRoutesCounter)

	//part2
	allRoutesCounter = 0
	getRoute(&routeMap, []string{"start"}, &allRoutesCounter, 2)
	fmt.Println(allRoutesCounter)
}

func getRoute(routeMap *map[string][]string, drivenRoute []string, allRoutesCounter *int, part int) {
	if drivenRoute[len(drivenRoute)-1] == "end" {
		*allRoutesCounter++
		return
	}

	position := drivenRoute[len(drivenRoute)-1]
	possibleNextSteps := []string{}
	for _, step := range (*routeMap)[position] {
		if !unicode.IsLower(rune(step[0])) || !(helper.ContainsString(step, drivenRoute) > 0) {
			possibleNextSteps = append(possibleNextSteps, step)
		} else if part == 2 && !checkRouteForDoubleVisitedSmallCaves(drivenRoute) {
			possibleNextSteps = append(possibleNextSteps, step)
		}
	}

	for _, step := range possibleNextSteps {
		newDrivenRoute := append(drivenRoute, step)
		getRoute(routeMap, newDrivenRoute, allRoutesCounter, part)
	}
}

func checkRouteForDoubleVisitedSmallCaves(route []string) bool {
	smallCavesCounter := make(map[string]int)
	for _, step := range route {
		if unicode.IsLower(rune(step[0])) && step != "end" {
			smallCavesCounter[step]++
			if smallCavesCounter[step] > 1 {
				return true
			}
		}
	}
	return false
}
