package main

import (
	"bufio"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

const (
	coords   = 3
	overlap  = 12
	rotation = 24
)

type scanLine struct {
	x, y, z int
}

type scanData struct {
	sPos    scanLine // position of the scanner (unknown)
	beacons []scanLine
}

type scanDatas []scanData

func main() {
	if err := myMain(); err != nil {
		log.Println(err)
	}
}

func myMain() error {
	sds, err := parseInput("input.txt")
	if err != nil {
		return err
	}

	log.Println(solveFirst(sds))

	return nil
}

func solveFirst(sds scanDatas) int {
	// store the absolute positions here
	absolutes := map[scanLine]struct{}{}

	// Scan 0 place and direction is 0,0,0 and 0 rotation. This is arbitrary.
	sds[0].sPos = scanLine{0, 0, 0}
	for _, s := range sds[0].beacons {
		absolutes[s] = struct{}{}
	}
	skip := make([]bool, len(sds))
	skip[0] = true

	for !allTrue(skip) {
	start:
		for scanNo := range sds {
			if skip[scanNo] {
				continue
			}
			for rot := 0; rot < rotation; rot++ {
				offsets := map[scanLine]int{}
				for _, sl := range sds[scanNo].beacons {
					for abs := range absolutes {
						tmp := sl.rotate(rot).sub(abs)
						offsets[tmp]++
						if offsets[tmp] >= overlap {
							// log.Println(tmp)
							sds[scanNo].sPos = scanLine{-tmp.x, -tmp.y, -tmp.z}
							for _, line := range sds[scanNo].beacons {
								absolutes[line.rotate(rot).sub(tmp)] = struct{}{}
							}
							skip[scanNo] = true
							continue start
						}
					}
				}
			}
		}
	}

	var max int
	for _, first := range sds {
		for _, second := range sds {
			if d := distance(first.sPos, second.sPos); d > max {
				max = d
			}
		}
	}
	log.Println(max)

	return len(absolutes)
}

func distance(first, second scanLine) int {
	return abs(first.x-second.x) + abs(first.y-second.y) + abs(first.z-second.z)
}

func abs(in int) int {
	if in < 0 {
		return -in
	}
	return in
}

func allTrue(in []bool) bool {
	for _, v := range in {
		if v != true {
			return false
		}
	}
	return true
}

func (s scanLine) sub(in scanLine) scanLine {
	return scanLine{s.x - in.x, s.y - in.y, s.z - in.z}
}

func (v scanLine) rotate(r int) scanLine {
	switch r {
	case 0:
		return scanLine{v.x, v.y, v.z}
	case 1:
		return scanLine{v.x, -v.z, v.y}
	case 2:
		return scanLine{v.x, -v.y, -v.z}
	case 3:
		return scanLine{v.x, v.z, -v.y}
	case 4:
		return scanLine{-v.x, -v.y, v.z}
	case 5:
		return scanLine{-v.x, -v.z, -v.y}
	case 6:
		return scanLine{-v.x, v.y, -v.z}
	case 7:
		return scanLine{-v.x, v.z, v.y}
	case 8:
		return scanLine{v.y, v.x, -v.z}
	case 9:
		return scanLine{v.y, -v.x, v.z}
	case 10:
		return scanLine{v.y, v.z, v.x}
	case 11:
		return scanLine{v.y, -v.z, -v.x}
	case 12:
		return scanLine{-v.y, v.x, v.z}
	case 13:
		return scanLine{-v.y, -v.x, -v.z}
	case 14:
		return scanLine{-v.y, -v.z, v.x}
	case 15:
		return scanLine{-v.y, v.z, -v.x}
	case 16:
		return scanLine{v.z, v.x, v.y}
	case 17:
		return scanLine{v.z, -v.x, -v.y}
	case 18:
		return scanLine{v.z, -v.y, v.x}
	case 19:
		return scanLine{v.z, v.y, -v.x}
	case 20:
		return scanLine{-v.z, v.x, -v.y}
	case 21:
		return scanLine{-v.z, -v.x, v.y}
	case 22:
		return scanLine{-v.z, v.y, v.x}
	case 23:
		return scanLine{-v.z, -v.y, -v.x}
	default:
		log.Panicln("no such rotation:", r)
		return scanLine{}
	}
}

func parseInput(fileName string) ([]scanData, error) {
	ret := []scanData{}
	fd, err := os.Open(fileName)
	if err != nil {
		return ret, err
	}
	defer fd.Close()

	re := regexp.MustCompile(`[-]*\d+`)

	buf := bufio.NewScanner(fd)
	sd := scanData{}
	for buf.Scan() {
		if buf.Text() == "" {
			ret = append(ret, sd)
			sd = scanData{}
			continue
		}

		if strings.HasPrefix(buf.Text(), "---") {
			continue
		}

		tmp := re.FindAllString(buf.Text(), -1)
		line := scanLine{}

		line.x, err = strconv.Atoi(tmp[0])
		if err != nil {
			return ret, err
		}
		line.y, err = strconv.Atoi(tmp[1])
		if err != nil {
			return ret, err
		}
		line.z, err = strconv.Atoi(tmp[2])
		if err != nil {
			return ret, err
		}

		sd.beacons = append(sd.beacons, line)
	}
	if len(sd.beacons) != 0 {
		ret = append(ret, sd)
	}

	return ret, nil
}