extends VBoxContainer
class_name FormField
## Form Field Component
##
## Combines label, input field, and error message display.
## Supports validation and different input types.
##
## Structure:
##   VBoxContainer
##   ├─ Label (field label)
##   ├─ LineEdit (input field)
##   └─ Label (error message, hidden by default)
##
## Usage:
##   var field = FormField.new()
##   field.label_text = "Email"
##   field.placeholder = "Enter your email"
##   field.input_type = FormField.InputType.EMAIL
##   field.value_changed.connect(_on_email_changed)

signal value_changed(new_value: String)
signal validation_changed(is_valid: bool)

# Input types
enum InputType {
	TEXT,      # Plain text
	EMAIL,     # Email validation
	PASSWORD,  # Password (hidden)
	NUMBER,    # Numeric only
	PHONE,     # Phone number
}

# Export variables
@export var label_text: String = ""
@export var placeholder: String = ""
@export var input_type: InputType = InputType.TEXT
@export var required: bool = false
@export var min_length: int = 0
@export var max_length: int = 0

# Internal nodes
var _label: Label = null
var _input: LineEdit = null
var _error_label: Label = null

# State
var _is_valid: bool = true
var _error_message: String = ""


func _ready() -> void:
	_setup_structure()
	_apply_styling()


## Setup form field structure
func _setup_structure() -> void:
	# Label
	_label = Label.new()
	_label.text = label_text
	add_child(_label)

	# Spacing
	var spacer1 = Control.new()
	spacer1.custom_minimum_size = Vector2(0, 4)
	add_child(spacer1)

	# Input field
	_input = LineEdit.new()
	_input.placeholder_text = placeholder
	_input.text_changed.connect(_on_text_changed)
	_input.text_submitted.connect(_on_text_submitted)

	# Set input type
	match input_type:
		InputType.PASSWORD:
			_input.secret = true
		InputType.NUMBER:
			# TODO: Add number-only filter
			pass
		_:
			pass

	# Set max length if specified
	if max_length > 0:
		_input.max_length = max_length

	add_child(_input)

	# Spacing
	var spacer2 = Control.new()
	spacer2.custom_minimum_size = Vector2(0, 2)
	add_child(spacer2)

	# Error label
	_error_label = Label.new()
	_error_label.visible = false
	add_child(_error_label)


## Apply styling
func _apply_styling() -> void:
	# Label styling
	_label.add_theme_color_override("font_color", ThemeColors.TEXT_PRIMARY)

	# Input styling
	var normal_style = StyleBoxFlat.new()
	normal_style.bg_color = ThemeColors.BACKGROUND_SECONDARY
	normal_style.border_width_all = 2
	normal_style.border_color = ThemeColors.BORDER_DEFAULT
	normal_style.corner_radius_all = 4
	normal_style.content_margin_left = 12
	normal_style.content_margin_right = 12
	normal_style.content_margin_top = 8
	normal_style.content_margin_bottom = 8
	_input.add_theme_stylebox_override("normal", normal_style)

	var focus_style = normal_style.duplicate()
	focus_style.border_color = ThemeColors.GOLD_ACCENT
	_input.add_theme_stylebox_override("focus", focus_style)

	_input.add_theme_color_override("font_color", ThemeColors.TEXT_PRIMARY)
	_input.add_theme_color_override("font_placeholder_color", ThemeColors.TEXT_SECONDARY)
	_input.add_theme_color_override("caret_color", ThemeColors.GOLD_ACCENT)

	# Error label styling
	_error_label.add_theme_color_override("font_color", ThemeColors.ERROR)
	# TODO: Add smaller font size when theme is set up


## Get current value
func get_value() -> String:
	return _input.text if _input else ""


## Set value
func set_value(value: String) -> void:
	if _input:
		_input.text = value
		_validate()


## Set label text
func set_label(text: String) -> void:
	label_text = text
	if _label:
		_label.text = text


## Set placeholder text
func set_placeholder(text: String) -> void:
	placeholder = text
	if _input:
		_input.placeholder_text = text


## Show error message
func show_error(message: String) -> void:
	_error_message = message
	_is_valid = false

	if _error_label:
		_error_label.text = message
		_error_label.visible = true

	# Change input border to error color
	if _input:
		var error_style = StyleBoxFlat.new()
		error_style.bg_color = ThemeColors.BACKGROUND_SECONDARY
		error_style.border_width_all = 2
		error_style.border_color = ThemeColors.ERROR
		error_style.corner_radius_all = 4
		error_style.content_margin_left = 12
		error_style.content_margin_right = 12
		error_style.content_margin_top = 8
		error_style.content_margin_bottom = 8
		_input.add_theme_stylebox_override("normal", error_style)

	validation_changed.emit(false)


## Clear error
func clear_error() -> void:
	_error_message = ""
	_is_valid = true

	if _error_label:
		_error_label.visible = false

	# Restore normal input styling
	_apply_styling()

	validation_changed.emit(true)


## Check if field is valid
func is_valid() -> bool:
	return _is_valid


## Focus the input field
func focus_input() -> void:
	if _input:
		_input.grab_focus()


## Validate the field
func validate() -> bool:
	return _validate()


## Internal: Validate input
func _validate() -> bool:
	var value = get_value()

	# Required check
	if required and value.is_empty():
		show_error("This field is required")
		return false

	# Min length check
	if min_length > 0 and value.length() < min_length:
		show_error("Must be at least %d characters" % min_length)
		return false

	# Max length check (redundant with LineEdit.max_length, but kept for consistency)
	if max_length > 0 and value.length() > max_length:
		show_error("Must be no more than %d characters" % max_length)
		return false

	# Type-specific validation
	match input_type:
		InputType.EMAIL:
			if not _is_valid_email(value) and not value.is_empty():
				show_error("Invalid email address")
				return false

		InputType.NUMBER:
			if not value.is_valid_int() and not value.is_empty():
				show_error("Must be a number")
				return false

		InputType.PHONE:
			if not _is_valid_phone(value) and not value.is_empty():
				show_error("Invalid phone number")
				return false

	# All validations passed
	clear_error()
	return true


## Internal: Email validation
func _is_valid_email(email: String) -> bool:
	# Basic email regex validation
	var regex = RegEx.new()
	regex.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")
	return regex.search(email) != null


## Internal: Phone validation
func _is_valid_phone(phone: String) -> bool:
	# Basic phone validation (digits, spaces, dashes, parentheses)
	var regex = RegEx.new()
	regex.compile("^[0-9\\s\\-\\(\\)\\+]+$")
	return regex.search(phone) != null and phone.length() >= 10


## Internal: Handle text change
func _on_text_changed(new_text: String) -> void:
	# Clear error when user starts typing
	if not _error_message.is_empty():
		clear_error()

	value_changed.emit(new_text)


## Internal: Handle text submission (Enter key)
func _on_text_submitted(new_text: String) -> void:
	_validate()
