extends Node2D

enum StructType {
	EMPTY_ROOM,                      # 0. Пустой модуль
	RESIDENTIAL_ROOM,                # 1. Жилой Модуль
	LABORATORY_ROOM,                 # 2. Лабораторный Модуль
	ENERGY_ROOM,                     # 3. Энергетический Модуль
	FARM_ROOM,                       # 4. Фермерский Модуль
	LIFE_SUPPORT_ROOM,               # 5. Модуль Жизнеобеспечения
	CONTROL_ROOM,                    # 6. Модуль Управления
	OBSERVATORY_ROOM,                # 7. Модуль Обсерватории
	MEDICAL_ROOM,                    # 8. Медицинский Модуль
	GEOLOGICAL_ROOM,                 # 9. Геологический Модуль
	RESOURCE_EXTRACTION_ROOM,        # 10. Модуль Добычи и Переработки Ресурсов
	COMMUNICATIONS_ROOM,              # 11. Модуль Связи и Навигации_
	
	V_WAY, H_WAY, WAY_UP, WAY_DOWN, WAY_LEFT, WAY_RIGHT,
}

enum struct_fields {
	SOURCE_ID,
	SIZE,
	POS_ATLAS,
	LAYER
}

@onready var structs = {
	StructType.EMPTY_ROOM: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(5,5),
		struct_fields.POS_ATLAS: Vector2i(0,0),
		struct_fields.LAYER: $buildings/buildings0
	},
	StructType.V_WAY: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(3,1),
		struct_fields.POS_ATLAS: Vector2i(0,6),
		struct_fields.LAYER: $buildings/buildings1
	},
	StructType.H_WAY: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(1,3),
		struct_fields.POS_ATLAS: Vector2i(4,5),
		struct_fields.LAYER: $buildings/buildings1
	},
	StructType.WAY_UP: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(3,1),
		struct_fields.POS_ATLAS: Vector2i(0,5),
		struct_fields.LAYER: $buildings/buildings1
	},
	StructType.WAY_DOWN: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(3,1),
		struct_fields.POS_ATLAS: Vector2i(0,7),
		struct_fields.LAYER: $buildings/buildings1
	},
	StructType.WAY_LEFT: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(1,3),
		struct_fields.POS_ATLAS: Vector2i(3,5),
		struct_fields.LAYER: $buildings/buildings1
	},
	StructType.WAY_RIGHT: {
		struct_fields.SOURCE_ID: 1,
		struct_fields.SIZE: Vector2i(1,3),
		struct_fields.POS_ATLAS: Vector2i(5,5),
		struct_fields.LAYER: $buildings/buildings1
	},
}

var layers: Array[TileMapLayer]
var layers_dict: Dictionary

func _list_childrens(node: Node2D):
	for child in node.get_children():
		if child is TileMapLayer:
			layers.append(child)
			layers_dict.get_or_add(child.name, child)
		elif child is Node2D:
			_list_childrens(child)
	pass

func _ready() -> void:
	layers = []
	_list_childrens(self)
	
func get_maxZ(tile_pos: Vector2i) -> int:
	var max_z: int = -1024
	for layer: TileMapLayer in layers:
		if layer.get_cell_source_id(tile_pos) != -1 and layer.z_index > max_z:
			max_z = layer.z_index
	return max_z

func get_toplayer(pos: Vector2i) -> TileMapLayer:
	var toplayer: TileMapLayer = null
	for layer: TileMapLayer in layers:
		if layer.get_cell_tile_data(pos) != null:
			if toplayer == null: toplayer = layer
			elif layer.z_index > toplayer.z_index: toplayer = layer
	return toplayer

func place_road(pos: Vector2i) -> bool:
	var layer: TileMapLayer = layers_dict["roads"]
	if get_maxZ(pos) >= layer.z_index:
		return false
	layer.set_cells_terrain_connect([pos], 0, 2, true)
	return true
func erase_road(pos: Vector2i) -> bool:
	var layer: TileMapLayer = layers_dict["roads"]
	layer.erase_cell(pos)
	return true

func place_way(pos1: Vector2i, pos2: Vector2i) -> bool:
	if pos1.x == pos2.x and pos1.y == pos2.y: return false
	if pos1.x != pos2.x and pos1.y != pos2.y: return false
	
	var tiledata1: TileData = layers_dict["buildings0"].get_cell_tile_data(pos1)
	var tiledata2: TileData = layers_dict["buildings0"].get_cell_tile_data(pos2)
	
	if tiledata1 == null or tiledata2 == null: return false
	
	if not (tiledata1.get_custom_data("is_center") and tiledata1.get_custom_data("struct_name")=="EMPTY_ROOM"): return false
	if not (tiledata2.get_custom_data("is_center") and tiledata2.get_custom_data("struct_name")=="EMPTY_ROOM"): return false
	
	#Check place is free
	if pos1.x != pos2.x:
		if abs(pos1.x-pos2.x)<=5: return false
		for x in range(min(pos1.x,pos2.x)+2, max(pos1.x,pos2.x)-1):
			if get_maxZ(Vector2i(x, pos1.y)) >= structs[StructType.H_WAY][struct_fields.LAYER].z_index:
					return false
	if pos1.y != pos2.y:
		if abs(pos1.y-pos2.y)<=5: return false
		for y in range(min(pos1.y,pos2.y)+2, max(pos1.y,pos2.y)-1):
			if get_maxZ(Vector2i(pos1.x, y)) >= structs[StructType.V_WAY][struct_fields.LAYER].z_index:
					return false
	
	
	if pos1.x != pos2.x:
		place_struct(Vector2i(min(pos1.x,pos2.x)+2, pos1.y), StructType.WAY_LEFT)
		place_struct(Vector2i(max(pos1.x,pos2.x)-2, pos1.y), StructType.WAY_RIGHT)
		for x in range(min(pos1.x,pos2.x)+3, max(pos1.x,pos2.x)-2):
			place_struct(Vector2i(x, pos1.y), StructType.H_WAY)
	if pos1.y != pos2.y:
		place_struct(Vector2i(pos1.x, min(pos1.y,pos2.y)+2), StructType.WAY_UP)
		place_struct(Vector2i(pos1.x, max(pos1.y,pos2.y)-2), StructType.WAY_DOWN)
		for y in range(min(pos1.y,pos2.y)+3, max(pos1.y,pos2.y)-2):
			place_struct(Vector2i(pos1.x, y), StructType.V_WAY)
	return true

func remove_struct(pos: Vector2i):
	for layer in layers:
		var tiledata: TileData = layer.get_cell_tile_data(pos)
		if tiledata != null and tiledata.get_custom_data("is_center"):
			var struct_size = tiledata.get_custom_data("struct_size")
			var half_size = Vector2i(struct_size.x / 2, struct_size.y / 2)
			for x in range(struct_size.x): 
				for y in range(struct_size.y):
					var offset = Vector2i(x, y)
					var tile_pos = pos+offset-half_size
					layer.erase_cell(tile_pos)
			return

func destroy_building(pos: Vector2i, only_ways: bool = false):
	for layer in layers:
		var tiledata: TileData = layer.get_cell_tile_data(pos)
		if tiledata != null and tiledata.get_custom_data("is_center"):
			if tiledata.get_custom_data("struct_name") == "H_WAY":
				remove_struct(pos)
				destroy_building(pos+Vector2i.LEFT)
				destroy_building(pos+Vector2i.RIGHT)
			elif tiledata.get_custom_data("struct_name") == "V_WAY":
				remove_struct(pos)
				destroy_building(pos+Vector2i.UP)
				destroy_building(pos+Vector2i.DOWN)
			elif not only_ways and tiledata.get_custom_data("struct_name") == "EMPTY_ROOM":
				remove_struct(pos)
				destroy_building(pos+Vector2i.LEFT*3, true)
				destroy_building(pos+Vector2i.RIGHT*3, true)
				destroy_building(pos+Vector2i.UP*3, true)
				destroy_building(pos+Vector2i.DOWN*3, true)
			elif not only_ways:
				remove_struct(pos)
			return

func place_struct(pos: Vector2i, type: StructType) -> bool:
	if not structs.has(type):
		return false
	var struct_size = structs[type][struct_fields.SIZE]
	var layer = structs[type][struct_fields.LAYER]
	var source_id = structs[type][struct_fields.SOURCE_ID]
	var pos_atlas = structs[type][struct_fields.POS_ATLAS]
	
	var half_size = Vector2i(struct_size.x / 2, struct_size.y / 2)
	
	#Is place free check
	for x in range(struct_size.x):
			for y in range(struct_size.y):
				var offset = Vector2i(x, y)
				var tile_pos = pos+offset-half_size
				if get_maxZ(tile_pos) >= layer.z_index:
					return false
					
	for x in range(struct_size.x):
			for y in range(struct_size.y):
				var offset = Vector2i(x, y)
				var tile_pos = pos+offset-half_size
				layer.set_cell(tile_pos, source_id, Vector2i(x,y)+pos_atlas)
	return true