package game

import (
	"fmt"

	"gitea.boner.be/bdnugget/goonscape/types"
)

type Node struct {
	Tile    types.Tile
	Parent  *Node
	G, H, F float32
}

func FindPath(start, end types.Tile) []types.Tile {
	openList := []*Node{}
	closedList := make(map[[2]int]bool)

	startNode := &Node{Tile: start, G: 0, H: heuristic(start, end)}
	startNode.F = startNode.G + startNode.H
	openList = append(openList, startNode)

	for len(openList) > 0 {
		current := openList[0]
		currentIndex := 0
		for i, node := range openList {
			if node.F < current.F {
				current = node
				currentIndex = i
			}
		}

		openList = append(openList[:currentIndex], openList[currentIndex+1:]...)
		closedList[[2]int{current.Tile.X, current.Tile.Y}] = true

		if current.Tile.X == end.X && current.Tile.Y == end.Y {
			path := []types.Tile{}
			node := current
			for node != nil {
				path = append([]types.Tile{node.Tile}, path...)
				node = node.Parent
			}
			fmt.Printf("Path found: %v\n", path)
			return path
		}

		neighbors := GetNeighbors(current.Tile)
		for _, neighbor := range neighbors {
			if !neighbor.Walkable || closedList[[2]int{neighbor.X, neighbor.Y}] {
				continue
			}

			tentativeG := current.G + distance(current.Tile, neighbor)
			inOpen := false
			var existingNode *Node
			for _, node := range openList {
				if node.Tile.X == neighbor.X && node.Tile.Y == neighbor.Y {
					existingNode = node
					inOpen = true
					break
				}
			}

			if !inOpen || tentativeG < existingNode.G {
				newNode := &Node{
					Tile:   neighbor,
					Parent: current,
					G:      tentativeG,
					H:      heuristic(neighbor, end),
				}
				newNode.F = newNode.G + newNode.H
				if !inOpen {
					openList = append(openList, newNode)
				}
			}
		}
	}
	return nil
}

func heuristic(a, b types.Tile) float32 {
	return float32(abs(a.X-b.X) + abs(a.Y-b.Y))
}

func distance(a, b types.Tile) float32 {
	_, _ = a, b
	return 1.0 // uniform cost for now
}

func GetNeighbors(tile types.Tile) []types.Tile {
	directions := [][2]int{
		{1, 0}, {-1, 0}, {0, 1}, {0, -1},
		{1, 1}, {-1, -1}, {1, -1}, {-1, 1},
	}
	neighbors := []types.Tile{}
	grid := GetMapGrid()
	for _, dir := range directions {
		nx, ny := tile.X+dir[0], tile.Y+dir[1]
		if nx >= 0 && nx < types.MapWidth && ny >= 0 && ny < types.MapHeight {
			if grid[nx][ny].Walkable {
				neighbors = append(neighbors, grid[nx][ny])
			}
		}
	}
	return neighbors
}

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