package main

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

func main() {
	args := os.Args[1:]
	input, err := helper.GetInput(args[0])
	if err != nil {
		fmt.Println(err)
	}
	enchanceAlg := input[0]
	picture := make([][]rune, len(input[2:]))
	for i, row := range input[2:] {
		picture[i] = []rune(row)
	}

	for i := 0; i < 50; i++ {
		if i%2 == 0 {
			picture = padPicture(picture, 10)
		}
		picture = enhancePicture(picture, enchanceAlg)
		if i%2 == 1 {
			picture = removeBorder(picture, 1)
		}
	}
	printPicture(picture)
	fmt.Println(countPixel(picture))
}

func enhancePicture(picture [][]rune, enchanceAlg string) [][]rune {
	newPicture := make([][]rune, len(picture))
	for i := 0; i < len(newPicture); i++ {
		newPicture[i] = make([]rune, len(picture[0]))
		for j := 0; j < len(newPicture[i]); j++ {
			newPicture[i][j] = rune(enchanceAlg[enchancePoint(picture, j, i)])
		}
	}
	return newPicture
}

func padPicture(picture [][]rune, n int) [][]rune {
	newPicture := make([][]rune, len(picture)+n*2)
	for i := 0; i < n; i++ {
		newPicture[i] = []rune(strings.Repeat(".", len(picture)+n*2))
	}
	for i := len(newPicture) - 1; i > len(newPicture)-n-1; i-- {
		newPicture[i] = []rune(strings.Repeat(".", len(picture)+n*2))
	}
	for i := n; i < len(newPicture)-n; i++ {
		newPicture[i] = []rune(strings.Repeat(".", n) + string(picture[i-n]) + strings.Repeat(".", n))
	}
	return newPicture
}

func removeBorder(picture [][]rune, n int) [][]rune {
	var newPicture [][]rune
	for _, row := range picture[n : len(picture)-n] {
		newPicture = append(newPicture, row[n:len(row)-n])
	}
	return newPicture
}

func enchancePoint(picture [][]rune, x int, y int) int {
	points := [9][2]int{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 0}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}
	var binaryNumber []rune
	for _, direction := range points {
		px := x + direction[1]
		py := y + direction[0]
		binaryPart := '0'
		if py < len(picture) && py >= 0 && px < len(picture[0]) && px >= 0 {
			if picture[py][px] == '#' {
				binaryPart = '1'
			}
		}
		binaryNumber = append(binaryNumber, binaryPart)
	}
	if i, err := strconv.ParseInt(string(binaryNumber), 2, 0); err != nil {
		return -1
	} else {
		return int(i)
	}
}

func printPicture(picture [][]rune) {
	fmt.Println("holla")
	for _, row := range picture {
		fmt.Println(string(row))
	}
	fmt.Println()
}

func countPixel(picture [][]rune) int {
	sum := 0
	for _, row := range picture {
		for _, char := range row {
			if char == '#' {
				sum++
			}
		}
	}
	return sum
}
