class_name CircuitValidator
extends Node
## Проверяет замкнутость цепи и вычисляет ток/напряжение.
## Используется менеджером уровня при нажатии "Запуск".

## Проверить, образуют ли элементы замкнутую цепь от источника к потребителю
static func validate_circuit(elements: Array[CircuitElement]) -> Dictionary:
	var result := {
		"is_closed": false,       # Цепь замкнута?
		"total_voltage": 0.0,     # Суммарное напряжение источников
		"total_resistance": 0.0,  # Суммарное сопротивление
		"current": 0.0,           # Ток в цепи
		"powered_consumers": []   # Запитанные потребители
	}

	# 1. Найти все источники
	var sources: Array[PowerSource] = []
	var consumers: Array[Consumer] = []
	for e in elements:
		if e is PowerSource:
			sources.append(e)
		elif e is Consumer:
			consumers.append(e)

	if sources.is_empty() or consumers.is_empty():
		return result

	# 2. Построить граф соединений
	# Элементы соединены, если их точки подключения совпадают
	var adjacency := _build_adjacency(elements)

	# 3. Для каждого источника проверить путь до каждого потребителя
	for source in sources:
		for consumer in consumers:
			if _has_path(source, consumer, adjacency, elements):
				result.is_closed = true
				result.total_voltage += source.get_voltage()
				result.powered_consumers.append(consumer)

	# 4. Подсчитать сопротивление
	for e in elements:
		if e is Resistor:
			result.total_resistance += e.resistance

	# Минимальное сопротивление (защита от деления на ноль)
	if result.total_resistance < 0.1:
		result.total_resistance = 0.1

	# 5. Закон Ома: I = V / R
	if result.is_closed:
		result.current = result.total_voltage / result.total_resistance

	return result


## Построить словарь смежности: элемент -> список соседних элементов
static func _build_adjacency(elements: Array[CircuitElement]) -> Dictionary:
	var adj := {}
	for e in elements:
		adj[e] = []

	# Для каждой пары элементов проверить, совпадают ли точки подключения
	for i in range(elements.size()):
		var points_i := elements[i].get_absolute_connection_points()
		for j in range(i + 1, elements.size()):
			var points_j := elements[j].get_absolute_connection_points()
			for pi in points_i:
				for pj in points_j:
					if pi == pj:
						adj[elements[i]].append(elements[j])
						adj[elements[j]].append(elements[i])

	return adj


## Поиск пути (BFS) между двумя элементами
static func _has_path(
	from: CircuitElement,
	to: CircuitElement,
	adjacency: Dictionary,
	elements: Array[CircuitElement]
) -> bool:
	var visited: Array[CircuitElement] = []
	var queue: Array[CircuitElement] = [from]
	visited.append(from)

	while not queue.is_empty():
		var current := queue.pop_front()
		if current == to:
			return true

		for neighbor in adjacency.get(current, []):
			if neighbor in visited:
				continue
			# Переключатель разрывает цепь, если выключен
			if neighbor is SwitchElement and not neighbor.conducts():
				continue
			visited.append(neighbor)
			queue.append(neighbor)

	return false
