extends Node

## GameManager - Main game coordinator singleton
## Bridges game state, visuals, and UI

signal game_ready
signal game_started
signal game_ended(winner_name: String)
signal turn_changed(player_name: String, turn_number: int)
signal phase_changed(phase_name: String)
signal card_played(card_data: Dictionary)
signal damage_dealt(player_name: String, amount: int)
signal message(text: String)
signal action_undone(action_name: String)
signal undo_available_changed(available: bool)

# Game state
var game_state: GameState = null

# Undo system
var undo_system: UndoSystem = null

# State flags
var is_initialized: bool = false
var is_game_active: bool = false

# Current input mode
enum InputMode {
	NONE,
	SELECT_CARD_TO_PLAY,
	SELECT_CP_SOURCE,
	SELECT_ATTACKER,
	SELECT_BLOCKER,
	SELECT_TARGET
}
var input_mode: InputMode = InputMode.NONE

# Selection tracking
var selected_card: CardInstance = null
var pending_action: Callable = func(): pass

func _ready() -> void:
	# Wait for CardDatabase to load
	if CardDatabase.get_all_cards().size() == 0:
		CardDatabase.database_loaded.connect(_on_database_loaded)
	else:
		_on_database_loaded()

func _on_database_loaded() -> void:
	is_initialized = true
	game_ready.emit()
	print("GameManager: Ready")

## Start a new game
func start_new_game() -> void:
	if not is_initialized:
		push_error("GameManager not initialized")
		return

	# Create new game state
	game_state = GameState.new()

	# Create undo system
	undo_system = UndoSystem.new(game_state)
	undo_system.undo_available_changed.connect(_on_undo_available_changed)
	undo_system.action_undone.connect(_on_action_undone)

	# Connect signals
	_connect_game_signals()

	# Create test decks
	var deck1 = CardDatabase.create_test_deck(0)
	var deck2 = CardDatabase.create_test_deck(1)

	# Setup and start
	game_state.setup_game(deck1, deck2)
	game_state.start_game()

	is_game_active = true
	game_started.emit()
	message.emit("Game started!")

## Connect to game state signals
func _connect_game_signals() -> void:
	game_state.game_ended.connect(_on_game_ended)
	game_state.card_played.connect(_on_card_played)
	game_state.damage_dealt.connect(_on_damage_dealt)
	game_state.forward_broken.connect(_on_forward_broken)
	game_state.attack_declared.connect(_on_attack_declared)
	game_state.block_declared.connect(_on_block_declared)
	game_state.combat_resolved.connect(_on_combat_resolved)

	game_state.turn_manager.turn_changed.connect(_on_turn_changed)
	game_state.turn_manager.phase_changed.connect(_on_phase_changed)

## Get current player
func get_current_player() -> Player:
	if game_state:
		return game_state.get_current_player()
	return null

## Get opponent
func get_opponent() -> Player:
	if game_state:
		return game_state.get_opponent()
	return null

## Check if it's a specific player's turn
func is_player_turn(player_index: int) -> bool:
	if game_state:
		return game_state.turn_manager.current_player_index == player_index
	return false

## Get current phase
func get_current_phase() -> Enums.TurnPhase:
	if game_state:
		return game_state.turn_manager.current_phase
	return Enums.TurnPhase.ACTIVE

## Try to play a card
func try_play_card(card: CardInstance) -> bool:
	if not game_state or not is_game_active:
		return false

	var player_index = card.controller_index
	if not is_player_turn(player_index):
		message.emit("Not your turn!")
		return false

	if not game_state.turn_manager.is_main_phase():
		message.emit("Can only play cards during Main Phase!")
		return false

	var player = game_state.get_player(player_index)

	# Check if we can afford the card
	if not player.cp_pool.can_afford_card(card.card_data):
		message.emit("Not enough CP!")
		# Enter CP generation mode
		input_mode = InputMode.SELECT_CP_SOURCE
		selected_card = card
		return false

	# Check play restrictions before attempting to play
	var play_error = _check_play_restrictions(player, card)
	if play_error != "":
		message.emit(play_error)
		return false

	# Determine target zone
	var to_zone = Enums.ZoneType.FIELD_FORWARDS if card.is_forward() else Enums.ZoneType.FIELD_BACKUPS

	# Try to play
	if game_state.play_card(player_index, card):
		# Record for undo
		if undo_system:
			undo_system.record_play_card(player_index, card, to_zone, {})

		message.emit("Played " + card.get_display_name())
		return true
	else:
		# This shouldn't happen if _check_play_restrictions works correctly
		# but provide context if it does
		message.emit("Failed to play " + card.get_display_name() + " (internal error)")
		return false

## Check play restrictions and return error message, or empty string if playable
func _check_play_restrictions(player: Player, card: CardInstance) -> String:
	# Check if card is in hand
	if not player.hand.has_card(card):
		return "Card is no longer in your hand!"

	# Check backup limit
	if card.is_backup():
		if player.field_backups.get_count() >= Player.MAX_BACKUPS:
			return "Cannot play: Maximum 5 Backups allowed!"

	# Check unique name restriction (non-generic cards)
	if not card.card_data.is_generic:
		if card.is_forward() and player.field_forwards.has_card_with_name(card.card_data.name):
			return "Cannot play: You already have " + card.card_data.name + " on the field!"
		if card.is_backup() and player.field_backups.has_card_with_name(card.card_data.name):
			return "Cannot play: You already have " + card.card_data.name + " on the field!"

	# Check Light/Dark restriction
	if card.is_light_or_dark():
		if player.field_forwards.has_light_or_dark() or player.field_backups.has_light_or_dark():
			return "Cannot play: You can only have one Light/Dark card on the field!"

	return ""

## Discard a card to generate CP
func discard_card_for_cp(card: CardInstance) -> bool:
	if not game_state or not is_game_active:
		return false

	var player_index = card.owner_index
	var element = card.get_element()

	if game_state.discard_for_cp(player_index, card):
		# Record for undo
		if undo_system:
			undo_system.record_discard_for_cp(player_index, card, element)

		message.emit("Discarded " + card.get_display_name() + " for 2 CP")
		_check_pending_action()
		return true

	return false

## Dull a backup to generate CP
func dull_backup_for_cp(card: CardInstance) -> bool:
	if not game_state or not is_game_active:
		return false

	var player_index = card.controller_index
	var element = card.get_element()

	if game_state.dull_backup_for_cp(player_index, card):
		# Record for undo
		if undo_system:
			undo_system.record_dull_backup_for_cp(player_index, card, element)

		message.emit("Dulled " + card.get_display_name() + " for 1 CP")
		_check_pending_action()
		return true

	return false

## Check if we can now afford the pending card
func _check_pending_action() -> void:
	if input_mode == InputMode.SELECT_CP_SOURCE and selected_card:
		var player = game_state.get_player(selected_card.controller_index)

		# Check if the card is still in hand (it may have been discarded for CP)
		if not player.hand.has_card(selected_card):
			message.emit("The card you wanted to play was discarded!")
			clear_selection()
			return

		if player.cp_pool.can_afford_card(selected_card.card_data):
			# Can now afford - try to play
			try_play_card(selected_card)
			clear_selection()

## Declare an attack
func declare_attack(card: CardInstance) -> bool:
	if not game_state or not is_game_active:
		return false

	if game_state.declare_attack(card):
		input_mode = InputMode.SELECT_BLOCKER
		return true

	return false

## Declare a block
func declare_block(card: CardInstance) -> bool:
	if not game_state or not is_game_active:
		return false

	if game_state.declare_block(card):
		game_state.resolve_combat()
		input_mode = InputMode.SELECT_ATTACKER
		return true

	return false

## Skip blocking
func skip_block() -> bool:
	if not game_state or not is_game_active:
		return false

	if game_state.skip_block():
		game_state.resolve_combat()
		input_mode = InputMode.SELECT_ATTACKER
		return true

	return false

## Pass priority / end current phase
func pass_priority() -> void:
	if not game_state or not is_game_active:
		return

	var phase = game_state.turn_manager.current_phase

	match phase:
		Enums.TurnPhase.MAIN_1, Enums.TurnPhase.MAIN_2:
			game_state.end_main_phase()
		Enums.TurnPhase.ATTACK:
			if game_state.turn_manager.attack_step == Enums.AttackStep.DECLARATION:
				game_state.end_attack_phase()
			elif game_state.turn_manager.attack_step == Enums.AttackStep.BLOCK_DECLARATION:
				skip_block()

	clear_selection()

## Clear current selection
func clear_selection() -> void:
	input_mode = InputMode.NONE
	selected_card = null
	pending_action = func(): pass

## Undo the last action
func undo_last_action() -> bool:
	if not undo_system:
		return false

	return undo_system.undo()

## Check if undo is available
func can_undo() -> bool:
	if not undo_system:
		return false
	return undo_system.can_undo()

## Get description of last undoable action
func get_undo_description() -> String:
	if not undo_system:
		return ""
	return undo_system.get_last_action_description()

## Restore the input mode based on the current phase
func restore_input_mode_for_phase() -> void:
	if not game_state:
		return

	var phase = game_state.turn_manager.current_phase
	match phase:
		Enums.TurnPhase.MAIN_1, Enums.TurnPhase.MAIN_2:
			input_mode = InputMode.SELECT_CARD_TO_PLAY
		Enums.TurnPhase.ATTACK:
			input_mode = InputMode.SELECT_ATTACKER
		_:
			input_mode = InputMode.NONE

## Signal handlers

func _on_undo_available_changed(available: bool) -> void:
	undo_available_changed.emit(available)

func _on_action_undone(action_name: String) -> void:
	message.emit("Undid: " + action_name)
	action_undone.emit(action_name)

func _on_game_ended(winner_index: int) -> void:
	is_game_active = false
	var winner_name = game_state.get_player(winner_index).player_name
	game_ended.emit(winner_name)
	message.emit(winner_name + " wins!")

func _on_card_played(card: CardInstance, _player_index: int) -> void:
	card_played.emit({
		"name": card.get_display_name(),
		"type": Enums.card_type_to_string(card.card_data.type)
	})

func _on_damage_dealt(player_index: int, amount: int, _cards: Array) -> void:
	var player_name = game_state.get_player(player_index).player_name
	damage_dealt.emit(player_name, amount)
	message.emit(player_name + " takes " + str(amount) + " damage!")

func _on_forward_broken(card: CardInstance) -> void:
	message.emit(card.get_display_name() + " was broken!")

func _on_attack_declared(attacker: CardInstance) -> void:
	message.emit(attacker.get_display_name() + " attacks!")

func _on_block_declared(blocker: CardInstance) -> void:
	message.emit(blocker.get_display_name() + " blocks!")

func _on_combat_resolved(_attacker: CardInstance, blocker: CardInstance) -> void:
	if blocker == null:
		message.emit("Attack hits!")
	else:
		message.emit("Combat resolved!")

func _on_turn_changed(player_index: int) -> void:
	var player = game_state.get_player(player_index)
	turn_changed.emit(player.player_name, game_state.turn_manager.turn_number)
	message.emit(player.player_name + "'s turn")

func _on_phase_changed(phase: Enums.TurnPhase) -> void:
	var phase_name = Enums.phase_to_string(phase)
	phase_changed.emit(phase_name)

	# Clear undo history on phase change
	if undo_system:
		undo_system.clear_history()

	# Set appropriate input mode
	match phase:
		Enums.TurnPhase.MAIN_1, Enums.TurnPhase.MAIN_2:
			input_mode = InputMode.SELECT_CARD_TO_PLAY
		Enums.TurnPhase.ATTACK:
			input_mode = InputMode.SELECT_ATTACKER
		_:
			input_mode = InputMode.NONE
