class_name OrderBoard
extends Node2D

# L'ardoise du restaurant. Elle ne décide de rien: elle montre ce que
# `GameState.order_board` contient. Toute la logique d'écriture vit là-bas,
# parce qu'un serveur et un cuisinier devront y accéder sans passer par un
# noeud de scène.

const WIDTH := 210.0
const LINE_HEIGHT := 28.0
const HEADER_HEIGHT := 34.0
const PADDING := 10.0

const FRAME_COLOR := Color("3d3049")
const BOARD_COLOR := Color("241d2e")
const RULE_COLOR := Color("574769")
const TITLE_COLOR := Color("ffd166")
const LINE_COLOR := Color("ece7f3")
const READY_COLOR := Color("7fcea5")
const EMPTY_COLOR := Color("857c92")

func _ready() -> void:
	z_index = -1
	GameState.state_changed.connect(queue_redraw)
	queue_redraw()

# Le panneau redessine à chaque frame où l'ardoise a bougé. `state_changed` ne
# couvre pas la cuisson d'un plat, qui change pourtant l'état « prêt » d'une
# ligne: on suit donc aussi le nombre d'assiettes prêtes.
var _ready_signature := ""

func _process(_delta: float) -> void:
	var signature := _compute_ready_signature()
	if signature != _ready_signature:
		_ready_signature = signature
		queue_redraw()

func _compute_ready_signature() -> String:
	var parts: Array[String] = []
	for node: Node in get_tree().get_nodes_in_group("dish"):
		if node is Dish and (node as Dish).state == Dish.State.FILLED:
			parts.append((node as Dish).recipe_id)
	parts.sort()
	return ",".join(parts)

# Une ligne est « prête » quand une assiette pleine de cette recette existe déjà
# quelque part. C'est déduit, jamais stocké: une assiette lavée ou jetée change
# la réponse sans que personne ait à mettre l'ardoise à jour.
func _recipe_is_plated(recipe_id: String) -> bool:
	for node: Node in get_tree().get_nodes_in_group("dish"):
		if node is Dish and (node as Dish).state == Dish.State.FILLED and (node as Dish).recipe_id == recipe_id:
			return true
	return false

func board_height() -> float:
	var slots := maxi(1, GameState.order_board_capacity())
	return HEADER_HEIGHT + float(slots) * LINE_HEIGHT + PADDING

func _draw() -> void:
	var height := board_height()
	var frame := Rect2(-WIDTH * 0.5 - 5.0, -5.0, WIDTH + 10.0, height + 10.0)
	draw_rect(frame, FRAME_COLOR)
	draw_rect(Rect2(-WIDTH * 0.5, 0.0, WIDTH, height), BOARD_COLOR)
	draw_rect(frame, RULE_COLOR, false, 2.0)

	var lines: Array = GameState.order_board
	var title := Loc.ui("ui.board.title") % [lines.size(), GameState.order_board_capacity()]
	draw_string(ThemeDB.fallback_font, Vector2(-WIDTH * 0.5 + PADDING, 22.0), title,
		HORIZONTAL_ALIGNMENT_LEFT, WIDTH - PADDING * 2.0, 15, TITLE_COLOR)
	draw_line(Vector2(-WIDTH * 0.5 + PADDING, HEADER_HEIGHT - 6.0),
		Vector2(WIDTH * 0.5 - PADDING, HEADER_HEIGHT - 6.0), RULE_COLOR, 1.5)

	if lines.is_empty():
		draw_string(ThemeDB.fallback_font, Vector2(-WIDTH * 0.5 + PADDING, HEADER_HEIGHT + 18.0),
			Loc.ui("ui.board.empty"), HORIZONTAL_ALIGNMENT_LEFT, WIDTH - PADDING * 2.0, 13, EMPTY_COLOR)
		return

	for index: int in range(lines.size()):
		var entry: Dictionary = lines[index]
		var recipe_id := str(entry.get("recipe", ""))
		var plated := _recipe_is_plated(recipe_id)
		var baseline := HEADER_HEIGHT + float(index) * LINE_HEIGHT + 18.0
		var label := Loc.ui("ui.board.line") % [int(entry.get("table", 0)) + 1, DataCatalog.recipe_name(recipe_id)]
		draw_string(ThemeDB.fallback_font, Vector2(-WIDTH * 0.5 + PADDING, baseline), label,
			HORIZONTAL_ALIGNMENT_LEFT, WIDTH - PADDING * 2.0 - 14.0, 13,
			READY_COLOR if plated else LINE_COLOR)
		# Une pastille marque la ligne dont l'assiette attend déjà: c'est ce qui
		# transforme l'ardoise en liste de courses plutôt qu'en simple rappel.
		if plated:
			draw_circle(Vector2(WIDTH * 0.5 - PADDING - 4.0, baseline - 4.0), 4.0, READY_COLOR)
