package main

import (
	"fmt"
	"time"

	helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)

const (
	DIR_N = '^'
	DIR_E = '>'
	DIR_S = 'v'
	DIR_W = '<'
)

func walk() {
	bot := NewBot(layout)
	for {
		x, y := bot.GetNextSpot()
		if bot.CanMove() && !bot.LastCoordWas(x, y) {
			bot.Move()
		} else {
			bot.TurnLeft()
			if bot.turns == 4 {
				break
			}
		}
		fmt.Print(helpers.CLEAR_SCREEN)
		fmt.Println(bot.pathCoords)
		bot.PrintLayout()
		time.Sleep(time.Second / 10)
	}
	fmt.Println(bot.path)
}

type Bot struct {
	X, Y       int
	Dir        byte
	layout     [][]byte
	path       string
	pathCoords []*helpers.Coordinate
	turns      int
	moves      int
}

func NewBot(layout [][]byte) *Bot {
	b := &Bot{layout: layout}
	// Find the bot
	for y := range b.layout {
		for x := range b.layout[y] {
			if isBot(b.layout[y][x]) {
				b.X = x
				b.Y = y
				b.Dir = b.layout[y][x]
				b.layout[y][x] = '#'
			}
		}
	}
	return b
}

func (b *Bot) Visited(x, y int) bool {
	for _, v := range b.pathCoords {
		if v.X == x && v.Y == y {
			return true
		}
	}
	return false
}

func (b *Bot) LastCoordWas(x, y int) bool {
	if len(b.pathCoords) == 0 {
		return false
	}
	c := b.pathCoords[len(b.pathCoords)-1]
	return c.X == x && c.Y == y
}

func (b *Bot) Move() bool {
	if !b.CanMove() {
		return false
	}
	b.pathCoords = append(b.pathCoords, helpers.NewCoordinate(b.X, b.Y))
	b.X, b.Y = b.GetNextSpot()
	if b.turns == 1 { // Left Turn
		b.path = b.path + ",L"
	} else if b.turns == 3 { // Right Turn
		b.path = b.path + ",R"
	}
	b.moves++
	b.turns = 0
	return true
}

func (b *Bot) GetNextSpot() (int, int) {
	testX, testY := b.X, b.Y
	switch b.Dir {
	case DIR_N:
		testY--
	case DIR_E:
		testX++
	case DIR_S:
		testY++
	case DIR_W:
		testX--
	}
	return testX, testY
}

func (b *Bot) CanMove() bool {
	x, y := b.GetNextSpot()
	if y < 0 || y >= len(b.layout) {
		return false
	}
	if x < 0 || x >= len(b.layout[y]) {
		return false
	}
	return b.layout[y][x] == '#'
}

func (b *Bot) TurnLeft() {
	switch b.Dir {
	case DIR_N:
		b.Dir = DIR_W
	case DIR_E:
		b.Dir = DIR_N
	case DIR_S:
		b.Dir = DIR_E
	case DIR_W:
		b.Dir = DIR_S
	}
	b.turns++
	if b.moves > 0 {
		b.path = b.path + "," + helpers.Itoa(b.moves)
		b.moves = 0
	}
}

func (b *Bot) TurnRight() {
	switch b.Dir {
	case DIR_N:
		b.Dir = DIR_E
	case DIR_E:
		b.Dir = DIR_S
	case DIR_S:
		b.Dir = DIR_W
	case DIR_W:
		b.Dir = DIR_N
	}
	b.turns++
	if b.moves > 0 {
		b.path = b.path + "," + helpers.Itoa(b.moves)
		b.moves = 0
	}
}

func isBot(b byte) bool {
	return b == DIR_N || b == DIR_E || b == DIR_S || b == DIR_W
}

func (b *Bot) PrintLayout() {
	for y := range b.layout {
		for x := range b.layout[y] {
			if x == b.X && y == b.Y {
				fmt.Print(string(b.Dir))
			} else if b.Visited(x, y) {
				fmt.Print("█")
			} else {
				fmt.Print(string(b.layout[y][x]))
			}
		}
		fmt.Println()
	}
}
