package main

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

func main() {
	args := os.Args[1:]
	input, err := helper.GetInput(args[0])
	if err != nil {
		fmt.Println(err)
	}
	intArray := make([][]int, len(input))
	for i,line := range input {
		runes := []rune(line)
		numbers := helper.RunesToNumber(runes)
		intArray[i] = numbers
	}
	part1(intArray)
	part2(intArray)

}

func part2(intArray [][]int) {
	oxygenGeneratorRating, _ := filterNumbersPart2(intArray, 0)
	co2ScrubberRating, _ := filterNumbersPart2(intArray, 1)
	fmt.Println(co2ScrubberRating * oxygenGeneratorRating)
}

func part1(intArray [][]int) {
	gammaArray := getGammaArray(intArray, 0)
	s, _ := json.Marshal(gammaArray)
	gammaString := strings.Replace(strings.Trim(string(s), "[]"),",","",-1)
	gamma, _ := strconv.ParseInt(gammaString, 2, 64)
	invertBinary, _ := strconv.ParseInt(strings.Repeat("1", len(gammaString)), 2, 64)
	fmt.Println(gamma * (gamma ^ invertBinary))
}

func filterNumbersPart2(intArray [][]int, invert int) (int64, error){
	intArrayCopy := make([][]int, len(intArray))
	copy(intArrayCopy, intArray)
	gammaArray := getGammaArray(intArrayCopy, invert)
	i := 0
	for len(intArrayCopy) > 1 {
		n := 0
		for _, number := range intArrayCopy {
			if number[i] == gammaArray[i] {
				intArrayCopy[n] = number
				n++
			}
		}
		intArrayCopy = intArrayCopy[:n]
		gammaArray = getGammaArray(intArrayCopy, invert)
		i++
	}
	s, _ := json.Marshal(intArrayCopy[0])
	intString := strings.Replace(strings.Trim(string(s), "[]"),",","",-1)
	return strconv.ParseInt(intString, 2, 64)
}

func getGammaArray(intArray [][]int, invert int) []int {
	transposedIntArray := helper.Transpose(intArray)
	var gammaArray []int
	for _, numbers := range transposedIntArray {
		gammaArray = append(gammaArray, getBit(numbers, len(transposedIntArray[0]), invert))
	}
	return gammaArray
}

func getBit(numbers []int, length int, invert int) int{
	sum := helper.AddNummbers(numbers...)
	returnvalue := 1
	if sum * 2 < length {
		returnvalue = 0
	}
	return returnvalue ^ invert
}
