package main

import (
	"AOC2021/src/helper"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

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

	sum := 0
	for _, line := range input {
		number, _ := getNumberForLine(line)
		sum += number
	}
	fmt.Println(sum)

}

func getNumberForLine(line string) (int, error){
	parsedLine := strings.Split(line, " | ")
	signals := strings.Split(parsedLine[0], " ")
	sort.Slice(signals, func(i, j int) bool {
		return len(signals[i]) < len(signals[j])
	})
	signalsToNumberMapper := setMapperValuesForUniqueSignalLenghts(signals)
	outputValues := strings.Split(parsedLine[1], " ")
	return getNumberForSignals(outputValues, signalsToNumberMapper)
}

func getNumberForSignals(outputValues []string, signalsToNumberMapper map[string]int) (int, error) {
	var sb strings.Builder
	for _, value := range outputValues {
		sb.WriteString(strconv.Itoa(signalsToNumberMapper[helper.SortString(value)]))
	}
	return strconv.Atoi(sb.String())
}

func setMapperValuesForUniqueSignalLenghts(signals []string) (signalsToNumberMapper map[string]int) {
	signalsToNumberMapper = make(map[string]int)
	signalToSignalMapper := make(map[rune]rune)
	signalsToNumberArray := [10]string{}
	signalsToNumberArray[1] = signals[0]
	signalsToNumberArray[4] = signals[2]
	signalsToNumberArray[7] = signals[1]
	signalsToNumberArray[8] = signals[9]

	//get a
	for _,singalFor7 := range signalsToNumberArray[7] {
		if !strings.ContainsRune(signalsToNumberArray[1], singalFor7) {
			signalToSignalMapper['a'] = singalFor7
		}
	}
	//get Signals for 5
	signalsForBAndD := helper.RemoveCharactersFromString(signalsToNumberArray[4], signalsToNumberArray[1])
	signalsToNumberArray[5] = getSignalsFor5(signals, signalsForBAndD)

	//get f
	for _,singalFor5 := range signalsToNumberArray[5] {
		if strings.ContainsRune(signalsToNumberArray[1], singalFor5) {
			signalToSignalMapper['f'] = singalFor5
		}
	}
	//get c
	for _,signalFor1 := range signalsToNumberArray[1] {
		if signalFor1 != signalToSignalMapper['f'] {
			signalToSignalMapper['c'] = signalFor1
		}
	}

	//get Signals for 3
	signalsToNumberArray[3] = getSignalsFor3(signals, signalsToNumberArray[1])

	//get Signals for 2
	signalsToNumberArray[2] = getSignalsFor2(signals,signalsToNumberArray[5],signalsToNumberArray[3])

	//get b
	signalToSignalMapper['b'] = rune(helper.RemoveCharactersFromString(signalsForBAndD, signalsToNumberArray[2])[0])

	//get d
	signalToSignalMapper['d'] = rune(helper.RemoveCharactersFromString(signalsForBAndD, string(signalToSignalMapper['b']))[0])

	//get 0
	signalsToNumberArray[0] = getSignalsFor0(signals, signalsToNumberArray[1], signalsToNumberArray[7], signalToSignalMapper['d'])

	//get Signals for 6 and 9
	signalsToNumberArray[6], signalsToNumberArray[9] = getSignalsFor6And9(signals,signalsToNumberArray[0], signalToSignalMapper['c'])

	for i,signal:= range signalsToNumberArray {
		signalsToNumberMapper[helper.SortString(signal)] = i
	}
	return
}

func getSignalsFor0(signals []string, signalsFor1 string, signalsFor7 string, signalForD rune) string {
	for _, signal := range signals[6:9] {
		if signal != signalsFor1 && signal != signalsFor7 && !strings.ContainsRune(signal, signalForD) {
			return signal
		}
	}
	return "No Signals Found"
}

func getSignalsFor2(signals []string, signalsFor5 string, signalsFor3 string) string {
	for _, signal := range signals[3:6] {
		if signal != signalsFor5 && signal != signalsFor3 {
			return signal
		}
	}
	return "No Signals Found"
}

func getSignalsFor3(signals []string, signalsFor1 string) string{
	for _, signal := range signals[3:6] {
		if helper.ContainsCharacter(signal, signalsFor1) {
			return signal
		}
	}
	return "No Signals Found"
}

func getSignalsFor5(signals []string, signalsForBAndD string) string {
	for _, signal := range signals[3:6] {
		if helper.ContainsCharacter(signal, signalsForBAndD) {
			return signal
		}
	}
	return "No Signals Found"
}

func getSignalsFor6And9(signals []string, signalsFor0 string, signalForC rune) (signalsFor6 string, signalsFor9 string) {
	for _, signal := range signals[6:9] {
		if signal != signalsFor0{
			if strings.ContainsRune(signal, signalForC) {
				signalsFor9 = signal
			} else{
				signalsFor6 = signal
			}
		}

	}
	return
}

func getSortedSignals(signals []string) [10]string{
	sortedSignals := [10]string{}
	for i, signal := range signals {
		sortedSignals[i] = helper.SortString(signal)
	}
	return sortedSignals
}

func part1(input []string) {
	sum := 0
	for _, line := range input {
		outputValues := strings.Split(strings.Split(line, " | ")[1], " ")
		for _, val := range outputValues {
			if len(val) == 2 || len(val) == 4 || len(val) == 3 || len(val) == 7 {
				sum++
			}
		}
	}
	fmt.Println(sum)
}
