@tool
extends Node3D
class_name HexMap

const BASE_TILE_SET_SCENE = preload('res://objects/map/tiles/base_hex_tile_set.tscn') as PackedScene

@export_tool_button("Load Map", "Callable") var load_map_action = load_map

@export var radius = 10

@onready var tile_set : HexTileSet = BASE_TILE_SET_SCENE.instantiate()

var empty_hex_tiles_coords : Array[Vector2i] = []
var hex_tiles_by_pos :  Dictionary[String, HexTile] = {}
var hex_tiles_by_id :  Dictionary[String, Array] = {}

func load_map():
    for c in get_children():
        c.queue_free()
    empty_hex_tiles_coords = []
    hex_tiles_by_pos = {}

    empty_hex_tiles_coords = get_all_hex_coords()
    empty_hex_tiles_coords.shuffle()

    var mandatory_tiles = tile_set.get_all_hex_tiles().filter(
        func (tile : HexTile): return tile.mandatory_tile
    )

    for hex_tile in mandatory_tiles:
        for i in range(hex_tile.mandatory_count):
            if len(empty_hex_tiles_coords) != 0:
                spawn_tile(
                    empty_hex_tiles_coords.pop_front(),
                    hex_tile
                )

    while len(empty_hex_tiles_coords) != 0:
        var coord : Vector2i = empty_hex_tiles_coords.pop_front() 
        spawn_tile(
            coord,
            get_available_tiles_for_coord(coord).pick_random()
        )
        
    

func spawn_tile(coord : Vector2i, hex_tile : HexTile):
    var new_tile = hex_tile.duplicate()

    hex_tiles_by_pos["%d:%d" % [coord.x, coord.y]] = new_tile
    if not (new_tile.name in hex_tiles_by_id):
        hex_tiles_by_id[new_tile.name] = []
    
    hex_tiles_by_id[new_tile.name].append(new_tile)

    new_tile.position = get_world_tile_coord(coord)

    new_tile.rotation.y = (randi() % 6)/6. * 2. * PI

    add_child(new_tile)

func get_available_tiles_for_coord(_coord : Vector2) -> Array[HexTile]:
    return tile_set.get_all_hex_tiles().filter(
        func (tile : HexTile): return not tile.mandatory_tile
    )

func get_all_hex_coords() -> Array[Vector2i]:
    var coords : Array[Vector2i] = []

    for x in range(-radius, radius):
        for y in range(-radius, radius):
            if Vector2(x,y).length() < radius:
                coords.append(Vector2i(x,y))
    
    return coords

func get_world_tile_coord(coord: Vector2i) -> Vector3:
    return Vector3(
        coord.x * HexTile.BASE_TILE_SIZE + (HexTile.BASE_TILE_SIZE/2. if coord.y%2 == 0 else 0.),
        0.,
        coord.y * HexTile.BASE_TILE_SIZE * cos(PI/6),
    )

func get_all_tiles_with_id(id : String) -> Array[HexTile]:
    if id in hex_tiles_by_id:
        return (hex_tiles_by_id[id] as Array[HexTile])
    return ([] as Array[HexTile])