extends CanvasLayer

# WoW-style chat overlay. T focuses "all" chat (visible to both teams), Y
# focuses "team" chat (visible only to players who share the sender's race —
# races double as teams, see TeamSelect). Enter sends, Escape cancels. Last
# MAX_LINES messages are kept, positioned bottom-left per overview/chat.md.

const MAX_LINES := 10
const HISTORY_W := 460.0
const HISTORY_H := 160.0
const INPUT_H := 30.0
const MARGIN_X := 16.0
const MARGIN_BOTTOM := 16.0
const GAP := 4.0

var _history: RichTextLabel
var _input_line: LineEdit
var _team_mode: bool = false
var _lines: Array[String] = []

@onready var _pause_menu = get_node_or_null("/root/World/PauseMenu")


func _ready() -> void:
	layer = 5
	_build_ui()
	ChatManager.message_received.connect(_on_message_received)


func _build_ui() -> void:
	# Positioned bottom-left via anchor 1.0 (actual window bottom edge), not
	# a hardcoded 800px design height — stretch mode is disabled (see
	# project.godot), so nothing scales/repositions automatically.
	var input_y2 := -MARGIN_BOTTOM
	var input_y1 := input_y2 - INPUT_H
	var history_y2 := input_y1 - GAP
	var history_y1 := history_y2 - HISTORY_H
	var x1 := MARGIN_X
	var x2 := MARGIN_X + HISTORY_W

	var panel := PanelContainer.new()
	var ps := StyleBoxFlat.new()
	ps.bg_color = Color(0.02, 0.03, 0.06, 0.55)
	ps.set_corner_radius_all(6)
	panel.add_theme_stylebox_override("panel", ps)
	panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
	# Anchors/offsets set as plain property assignments, not sequential
	# set_anchor_and_offset() calls — that method's default
	# push_opposite_anchor=true drags the opposite side along when the two
	# calls momentarily disagree (e.g. top set to anchor 1.0 while bottom is
	# still its 0.0 default), corrupting layout. See team_select.gd's
	# _place() for the fuller writeup of this bug.
	panel.anchor_left = 0.0
	panel.anchor_right = 0.0
	panel.anchor_top = 1.0
	panel.anchor_bottom = 1.0
	panel.offset_left = x1
	panel.offset_right = x2
	panel.offset_top = history_y1
	panel.offset_bottom = history_y2
	add_child(panel)

	_history = RichTextLabel.new()
	_history.bbcode_enabled = true
	_history.scroll_active = true
	_history.scroll_following = true
	_history.mouse_filter = Control.MOUSE_FILTER_IGNORE
	_history.add_theme_font_size_override("normal_font_size", 15)
	_history.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
	_history.offset_left = 8
	_history.offset_top = 4
	_history.offset_right = -8
	_history.offset_bottom = -4
	panel.add_child(_history)

	_input_line = LineEdit.new()
	_input_line.anchor_left = 0.0
	_input_line.anchor_right = 0.0
	_input_line.anchor_top = 1.0
	_input_line.anchor_bottom = 1.0
	_input_line.offset_left = x1
	_input_line.offset_right = x2
	_input_line.offset_top = input_y1
	_input_line.offset_bottom = input_y2
	_input_line.max_length = ChatManager.MAX_MESSAGE_LENGTH
	var ib := StyleBoxFlat.new()
	ib.bg_color = Color(0.02, 0.03, 0.06, 0.85)
	ib.set_corner_radius_all(4)
	ib.set_border_width_all(1)
	ib.border_color = Color(0.3, 0.5, 0.75, 0.8)
	_input_line.add_theme_stylebox_override("normal", ib)
	_input_line.add_theme_stylebox_override("focus", ib)
	_input_line.add_theme_font_size_override("font_size", 15)
	_input_line.caret_blink = true
	_input_line.caret_blink_interval = 0.5
	_input_line.caret_force_displayed = true
	_input_line.add_theme_color_override("caret_color", Color(0.7, 0.9, 1.0))
	_input_line.add_theme_constant_override("caret_width", 9)
	_input_line.visible = false
	_input_line.text_submitted.connect(_on_text_submitted)
	_input_line.focus_exited.connect(_close_chat)
	add_child(_input_line)


func _input(event: InputEvent) -> void:
	if not _input_line.visible:
		if _pause_menu and _pause_menu.is_paused():
			return
		if event.is_action_pressed("chat_all"):
			_open_chat(false)
			get_viewport().set_input_as_handled()
		elif event.is_action_pressed("chat_team"):
			_open_chat(true)
			get_viewport().set_input_as_handled()
	elif event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE:
		_close_chat()
		get_viewport().set_input_as_handled()


func _open_chat(team_only: bool) -> void:
	_team_mode = team_only
	_input_line.placeholder_text = "[TEAM] Message..." if team_only else "Message..."
	_input_line.text = ""
	_input_line.visible = true
	_input_line.grab_focus()
	GameConfig.chat_focused = true


func _close_chat() -> void:
	_input_line.visible = false
	if _input_line.has_focus():
		_input_line.release_focus()
	GameConfig.chat_focused = false


func _on_text_submitted(text: String) -> void:
	ChatManager.send_chat(text, _team_mode)
	_close_chat()


func _on_message_received(sender_name: String, sender_race: int, team_only: bool, text: String) -> void:
	var safe_text := _escape_bbcode(text)
	var line: String
	if sender_name == ChatManager.ADMIN_NAME:
		line = "[color=#e0c341]* %s[/color]" % safe_text
	else:
		var name_color := _race_color(sender_race).to_html(false)
		var safe_name := _escape_bbcode(sender_name)
		if team_only:
			line = "[color=#7fdc7f][TEAM][/color] [color=#%s]%s[/color]: %s" % [name_color, safe_name, safe_text]
		else:
			line = "[color=#%s]%s[/color]: %s" % [name_color, safe_name, safe_text]

	_lines.append(line)
	if _lines.size() > MAX_LINES:
		_lines.pop_front()
	_history.text = "\n".join(_lines)


func _race_color(race_id: int) -> Color:
	for race in TeamSelect.RACES:
		if race.id == race_id:
			return race.color
	return Color(0.85, 0.87, 0.92)


func _escape_bbcode(s: String) -> String:
	return s.replace("[", "[lb]")
