extends Node
class_name IsometricMapRenderer

var map_data = null
var isometric_map_layers = []
var highlighted_tiles = {}  # Dictionary to store all currently highlighted tiles

var TILE_SIZE_ISOMETRIC_X = 32 # in px
var TILE_SIZE_ISOMETRIC_Y = 16 # in px

var unit_is_hovered = false
var unit_is_selected = false


var darkening_active = false
var original_modulates = {}

func darken_all_except_player(player_node):
    darkening_active = true
    
    # Store original modulate values
    for layer in isometric_map_layers:
        original_modulates[layer] = layer.modulate
        # Darken the layer
        layer.modulate = Color(0.5, 0.5, 0.5, 1.0)
    
    # Keep player at normal brightness
    player_node.modulate = Color(1.0, 1.0, 1.0, 1.0)

func reset_darkening():
    darkening_active = false
    
    # Restore original modulate values
    for layer in isometric_map_layers:
        if layer in original_modulates:
            layer.modulate = original_modulates[layer]

func set_unit_hover_state(is_hovered):
    unit_is_hovered = is_hovered
    
func set_unit_selected_state(is_selected):
    unit_is_selected = is_selected

# Initialize with reference to a map data object and a tilemap to use as template
func _init(map_data_ref, tilemap_template):
    map_data = map_data_ref
    initialize_map_layers(tilemap_template)

# Initialize all the map layers for different heights
func initialize_map_layers(tilemap_template):
    # Clear any existing layers
    for layer in isometric_map_layers:
        if is_instance_valid(layer):
            layer.queue_free()
    
    isometric_map_layers.clear()
    
    # Create new layers for each height level
    for z in map_data.GRID_SIZE_HEIGHT:
        var new_layer = TileMapLayer.new()
        new_layer.set_name("IsometricMapLayer_" + str(z))
        new_layer.tile_set = tilemap_template.tile_set
        new_layer.z_index = z  # Set the z-index to match the layer's height
        
        tilemap_template.get_parent().add_child(new_layer)
        isometric_map_layers.append(new_layer)

# Draw all visible tiles on the map
func draw_visible_tiles():
    # Clear all previously drawn tiles on each layer
    for layer in isometric_map_layers:
        layer.clear()
    
    # Draw the map
    for z in map_data.GRID_SIZE_HEIGHT:
        for y in map_data.GRID_SIZE_LENGTH:
            for x in map_data.GRID_SIZE_WIDTH:
                var tile = map_data.get_tile(x, y, z)
                if tile != null and tile["visibility"] and tile["atlas_base_position"] != null:
                    # Use the layer that corresponds to the tile's z-value
                    if z < isometric_map_layers.size():
                        isometric_map_layers[z].set_cell(
                            Vector2i(tile["x"], tile["y"]), 
                            IsometricMapSystem.MAIN_SOURCE_ID, 
                            tile["atlas_base_position"]
                        )

# Handle hovering over tiles
func handle_hover(mouse_position):
    var hover_tile_position = isometric_map_layers[0].local_to_map(mouse_position)
    var new_highlighted_tiles = {}  # Will store tiles to highlight this frame
    
    if unit_is_hovered:
        # De-highlight all tiles
        for tile_key in highlighted_tiles:
            var tile_data = highlighted_tiles[tile_key]
            var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
            
            if tile != null and tile["visibility"] and not tile["unit"]:
                if not tile["selected"]:
                    if tile["atlas_base_position"] != null:
                        isometric_map_layers[tile_data.z].set_cell(
                            Vector2i(tile["x"], tile["y"]), 
                            IsometricMapSystem.MAIN_SOURCE_ID, 
                            tile["atlas_base_position"]
                        )
                tile["highlighted"] = false
        
        highlighted_tiles = {}
        return
    
    # First find all tiles that should be highlighted
    for z in map_data.GRID_SIZE_HEIGHT:
        for x in map_data.GRID_SIZE_WIDTH:
            for y in map_data.GRID_SIZE_LENGTH:
                var tile = map_data.get_tile(x, y, z)
                
                if tile != null and tile["visibility"] and not tile["unit"]:
                    if tile["x"] == hover_tile_position.x and tile["y"] == hover_tile_position.y:
                        # Store this tile for highlighting
                        var tile_key = str(x) + "_" + str(y) + "_" + str(z)
                        
                        new_highlighted_tiles[tile_key] = {
                            "x": x, 
                            "y": y, 
                            "z": z
                        }
    
    # Highlight new tiles
    for tile_key in new_highlighted_tiles:
        var tile_data = new_highlighted_tiles[tile_key]
        var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
        if tile == null:
            continue
            
        if not tile["selected"] and not tile["unit"]:
            # Only set cell if we have a valid highlight position
            if tile["atlas_highlight_position"] != null:
                isometric_map_layers[tile_data.z].set_cell(
                    Vector2i(tile["x"], tile["y"]), 
                    IsometricMapSystem.MAIN_SOURCE_ID, 
                    tile["atlas_highlight_position"]
                )
        else:
            isometric_map_layers[tile_data.z].set_cell(
                Vector2i(tile["x"], tile["y"]), 
                1, 
                Vector2i(3,1) #  
            )
                
        tile["highlighted"] = true
    
    # De-highlight tiles that are no longer under the cursor
    for tile_key in highlighted_tiles:
        if not (tile_key in new_highlighted_tiles):
            var tile_data = highlighted_tiles[tile_key]
            var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z)
            
            if tile != null and tile["visibility"] and not tile["unit"]:
                
                if not tile["selected"]:
                    # Only set cell if we have a valid base position
                    if tile["atlas_base_position"] != null:
                        isometric_map_layers[tile_data.z].set_cell(
                            Vector2i(tile["x"], tile["y"]), 
                            IsometricMapSystem.MAIN_SOURCE_ID, 
                            tile["atlas_base_position"]  # Original appearance
                        )
                else:
                    isometric_map_layers[tile_data.z].set_cell(
                        Vector2i(tile["x"], tile["y"]), 
                        1, 
                        Vector2i(0,1) #  
                    )
                tile["highlighted"] = false
    
    # Update the highlighted tiles list
    highlighted_tiles = new_highlighted_tiles

# Handle tile selection logic
func handle_tile_selection():
    if unit_is_selected:
        reset_darkening()
        unit_is_selected = false    
    
    for z in map_data.GRID_SIZE_HEIGHT:
        for x in map_data.GRID_SIZE_WIDTH:
            for y in map_data.GRID_SIZE_LENGTH:
                var tile = map_data.get_tile(x, y, z)
                if tile == null or not tile["visibility"]:
                    continue
                
                # Get valid coordinates
                var tile_x = tile["x"]
                var tile_y = tile["y"]
                
                if tile["selected"] and tile["highlighted"]:
                    print("direct de selected: ", Vector2i(tile_x, tile_y))
                    isometric_map_layers[z].set_cell(
                        Vector2i(tile_x, tile_y), 
                        IsometricMapSystem.MAIN_SOURCE_ID, 
                        IsometricMapSystem.SELECTED_BLUE_ISOMETRICTILE_ATLAS_POSITION 
                    )
                    tile["selected"] = false
                
                elif tile["selected"] and not tile["highlighted"]:
                    print("old de selected: ", Vector2i(tile_x, tile_y))
                    # If there's a base position, restore it, otherwise use a default
                    if tile["atlas_base_position"] != null:
                        isometric_map_layers[z].set_cell(
                            Vector2i(tile_x, tile_y), 
                            IsometricMapSystem.MAIN_SOURCE_ID, 
                            tile["atlas_base_position"]
                        )
                    else:
                        isometric_map_layers[z].set_cell(
                            Vector2i(tile_x, tile_y), 
                            IsometricMapSystem.MAIN_SOURCE_ID, 
                            IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION
                        )
                    tile["selected"] = false
                
                elif not tile["selected"] and tile["highlighted"]:
                    print("new selected: ", Vector2i(tile_x, tile_y))
                    isometric_map_layers[z].set_cell(
                        Vector2i(tile_x, tile_y), 
                        IsometricMapSystem.MAIN_SOURCE_ID, 
                        IsometricMapSystem.SELECTED_WHITE_ISOMETRICTILE_ATLAS_POSITION
                    )
                    tile["selected"] = true

# Position a unit on the map visually
func position_unit(unit, tile_x, tile_y, tile_z):
    var world_pos = IsometricMapSystem.iso_to_world(
        tile_x, 
        tile_y, 
        tile_z,
        TILE_SIZE_ISOMETRIC_X,
        TILE_SIZE_ISOMETRIC_Y
    )
    
    unit.z_index = tile_z
    # Assuming unit has a set_unit_position method to handle actual positioning
    if unit.has_method("set_unit_position"):
        unit.set_unit_position(world_pos.x, world_pos.y, tile_z)
