package day19

import (
	"sort"
	"strings"
)

func Part1(input string) int {
	in := strings.Split(input, "\n\n")
	towels := strings.Split(in[0], ", ")
	patterns := strings.Split(in[1], "\n")
	//	fmt.Println(towels, patterns)
	count := 0
	not_possibles := make(map[string]bool)
	for _, pattern := range patterns {
		if isPossible(towels, pattern, not_possibles) {
			//			fmt.Println(count, pattern)
			count++
		}
	}
	return count
}

func Part2(input string) int {
	in := strings.Split(input, "\n\n")
	towels := strings.Split(in[0], ", ")
	sort.Strings(towels)
	patterns := strings.Split(in[1], "\n")
	//	fmt.Println(towels, patterns)
	count := 0
	memo := make(map[string]int)
	for _, pattern := range patterns {
		count += countPossible(sortStringsByPrefix(towels), pattern, memo)
	}
	return count
}

func isPossible(towels []string, pattern string, not_possibles map[string]bool) bool {
	if pattern == "" {
		return true
	}
	if not_possibles[pattern] {
		return false
	}
	for _, towel := range towels {
		if strings.HasPrefix(pattern, towel) {
			if isPossible(towels, pattern[len(towel):], not_possibles) {
				return true
			}
		}
	}
	not_possibles[pattern] = true
	return false
}

func countPossible(towels map[byte][]string, pattern string, memo map[string]int) int {
	if pattern == "" {
		return 1
	}

	//If memo has key
	if val, ok := memo[pattern]; ok {
		return val
	}

	count := 0
	for _, towel := range towels[pattern[0]] {
		if strings.HasPrefix(pattern, towel) {
			count += countPossible(towels, pattern[len(towel):], memo)
		}
	}

	memo[pattern] = count

	return count
}

func sortStringsByPrefix(slice []string) map[byte][]string {
	result := make(map[byte][]string)
	for _, str := range slice {
			result[str[0]] = append(result[str[0]], str)
		}
	for _, t := range result {
		sort.Strings(t)
	}
	return result
}
