package day11

import (
	"adventofcode2023/utils"
	_ "fmt"
	"strings"
)

type Galaxy struct {
	x int
	y int
}

func Part1(input string) int {
	galaxies := []Galaxy{}
	lines := strings.Split(input, "\n")
	var expand_rows []int
	var expand_cols []int
	for y,line := range lines {
		for x,char := range line {
			if char == '#' {
				galaxies = append(galaxies, Galaxy{x, y})
			}
		}
	}
	// fmt.Println(galaxies)
	for y,line := range lines {
		no_galaxy := true
		for _,char := range line {
			if char != '.' {
				no_galaxy = false
				break
			}
		}
		if no_galaxy {
			expand_rows = append(expand_rows, y)
		}
	}
	for x:=0;x<len(lines[0]);x++ {
		no_galaxy := true
		for _,line := range lines {
				if line[x] != '.' {
					no_galaxy = false
					break
				}
		}
		if no_galaxy {
			expand_cols = append(expand_cols, x)
		}
	}
	galaxies = expand_row(expand_rows, galaxies, true)
	galaxies = expand_col(expand_cols, galaxies, true)
//	fmt.Printf("r: %v c: %v\n%v\n", expand_rows, expand_cols, galaxies)
	dist := 0
	for i:=0;i<len(galaxies)-1;i++{
		g1 := galaxies[i]
		for _, g2 := range galaxies[i+1:] {
			dist = dist + distance(g1, g2)
		}
	}
	return dist
}

func Part2(input string) int {
	galaxies := []Galaxy{}
	lines := strings.Split(input, "\n")
	var expand_rows []int
	var expand_cols []int
	for y,line := range lines {
		for x,char := range line {
			if char == '#' {
				galaxies = append(galaxies, Galaxy{x, y})
			}
		}
	}
//	fmt.Println(galaxies)
	for y,line := range lines {
		no_galaxy := true
		for _,char := range line {
			if char != '.' {
				no_galaxy = false
				break
			}
		}
		if no_galaxy {
			expand_rows = append(expand_rows, y)
		}
	}
	for x:=0;x<len(lines[0]);x++ {
		no_galaxy := true
		for _,line := range lines {
				if line[x] != '.' {
					no_galaxy = false
					break
				}
		}
		if no_galaxy {
			expand_cols = append(expand_cols, x)
		}
	}
	galaxies = expand_row(expand_rows, galaxies, false)
	galaxies = expand_col(expand_cols, galaxies, false)
//	fmt.Printf("r: %v c: %v\n%v\n", expand_rows, expand_cols, galaxies)
	dist := 0
	for i:=0;i<len(galaxies)-1;i++{
		g1 := galaxies[i]
		for _, g2 := range galaxies[i+1:] {
			dist = dist + distance(g1, g2)
		}
	}
	return dist
}

func expand_row(rows []int, galaxies []Galaxy, partOne bool) []Galaxy {
	new := []Galaxy{}
	for _,galaxy := range galaxies {
		new = append(new, Galaxy{galaxy.x, galaxy.y + howMany(rows, galaxy.y, partOne)})
	}
	return new
}

func expand_col(cols []int, galaxies []Galaxy, partOne bool) []Galaxy {
	new := []Galaxy{}
	for _,galaxy := range galaxies {
		new = append(new, Galaxy{galaxy.x  + howMany(cols, galaxy.x, partOne), galaxy.y})
	}
	return new
}

func howMany(xs []int, a int, partOne bool) int {
	count := 0
	incr := 1
	if !partOne { incr = 1000000 - 1 }
	for _,x := range xs {
		if x < a {
			count = count + incr
		}
	}
	return count
}

func distance(g1 Galaxy, g2 Galaxy) int {
	val := utils.Abs(g1.x - g2.x) + utils.Abs(g1.y - g2.y)
//	fmt.Printf("%v - %v = %v\n", g1, g2, val)
	return val
}