class_name BattleScene extends Node3D

@export var actionBox:ActionBox = null
@export var battleFighterScenes:Node
@export var cursorScenes:Node

signal neverEmitted

func _init() ->void:
  BATTLE.battleScene = self
  BATTLE.battleStarted.connect(onBattleStarted)

func onBattleStarted() -> void:
  pass

func getBattleDecisions(fighters:Array[BattleFighter]) -> Array[BattleDecision]:
  var decisions:Array[BattleDecision] = []

  while fighters.size() > decisions.size():
    var fighter = fighters[decisions.size()]
    var decision:BattleDecision = null

    # Simulate walking forward animation like in Final Fantasy
    await get_tree().create_timer(0.5).timeout

    # Until decision made...
    while decision == null:
      # Get the selected action
      actionBox.visible = true
      var action = await self.actionBox.getAction(fighter)
      
      # Go back to previous fighter
      if action == ActionBox.Action.BACK:
        decisions.pop_back()
        actionBox.visible = false
      # Get target for attack
      elif action == ActionBox.Action.ATTACK:
        var targets = await _getTargets(fighter, fighter.movePrimary)
        decision = BattleDecision.new(
          fighter.movePrimary,
          fighter,
          targets
        )
      # Get Magic move and targets
      elif action == ActionBox.Action.MAGIC:
        var magicMove = await _getMagicMove(fighter)
        if magicMove != null:
          var targets = await _getTargets(fighter, magicMove)
          decision = BattleDecision.new(
            magicMove,
            fighter,
            targets
          )
      # Get Item use and targets
      elif action == ActionBox.Action.ITEM:
        var itemMove = await _getItemUse(fighter)
        if itemMove != null:
          var targets = await _getTargets(fighter, itemMove)
          decision = BattleDecision.new(
            itemMove,
            fighter,
            targets
          )

    if decision != null:
      decisions.append(decision)

  # Return the made decision
  return decisions

func _getInitialTargetPosition(
  fighter:BattleFighter,
  move:BattleAction,
  possiblePositions:Array[BattleSingleton.BattlePosition],
) -> BattleSingleton.BattlePosition:
  # Find ally in possible positions
  if move.preferAlly:
    for pos in possiblePositions:
      var targetFighter = BATTLE.getFighterAtPosition(pos)
      if targetFighter != null and targetFighter.team == fighter.team:
        return pos

  # Otherwise, prefer to target enemy
  for pos in possiblePositions:
    var targetFighter = BATTLE.getFighterAtPosition(pos)
    if targetFighter != null and targetFighter.team != fighter.team:
      return pos

  # If still noting found, just return first possible position
  if possiblePositions.size() > 0:
    return possiblePositions[0]

  # Fallback (should not happen)
  assert(false)
  return BATTLE.BattlePosition.LEFT_TOP_BACK

func _getTargets(fighter:BattleFighter, move:BattleAction) -> Array[BattleFighter]:
  assert(fighter != null)
  assert(move != null)

  # Determine possible targets and whether to blink or not
  var possiblePositions:Array[BattleSingleton.BattlePosition] = []

  if move.canTargetEnemy:
    possiblePositions.append_array(BATTLE.getEnemyPositions())
  if move.canTargetAlly:
    possiblePositions.append_array(BATTLE.getAllyPositions())

  # Should not be possible to have no possible targets here
  assert(possiblePositions.size() > 0)

  var activePositions:Array[BattleSingleton.BattlePosition] = [
    _getInitialTargetPosition(fighter, move, possiblePositions)
  ]

  # This is where output will be stored.
  var selectedPositions:Array[BattleSingleton.BattlePosition] = []

  # Here we wait for a selection to be confirmed.
  while selectedPositions.size() == 0:
    var blink = activePositions.size() > 1

    # Show cursors
    for cursor in cursorScenes.get_children():
      if !(cursor is BattleCursorIcon):
        continue
      if cursor.battlePosition in activePositions:
        if blink:
          cursor.mode = BattleCursorIcon.Mode.BLINKING
        else:
          cursor.mode = BattleCursorIcon.Mode.ACTIVE
      else:
        cursor.mode = BattleCursorIcon.Mode.INACTIVE
    
    # Handle movement
    

    # TODO: Allow movement here, wait for selection, etc.
    # Wait 1 second for now and select all possible targets
    await get_tree().create_timer(1.0).timeout
    # selectedPositions = possiblePositions
    
  # By this point selection has been made, hide all cursors
  for cursor in cursorScenes.get_children():
    if !(cursor is BattleCursorIcon):
      continue
    cursor.mode = BattleCursorIcon.Mode.INACTIVE

  # Convert selected positions to fighters
  var targets:Array[BattleFighter] = []
  for pos in selectedPositions:
    var targetFighter = BATTLE.getFighterAtPosition(pos)
    if targetFighter != null:
      targets.append(targetFighter)

  # Should not be possible to have no targets here
  assert(targets.size() > 0)
  return targets

func _getMagicMove(fighter:BattleFighter) -> BattleAction:
  return null

func _getItemUse(fighter:BattleFighter) -> BattleAction:
  return null

func getFighterSceneAtPosition(pos:BattleSingleton.BattlePosition) -> BattleFighterScene:
  for fighterScene in battleFighterScenes.get_children():
    if !(fighterScene is BattleFighterScene):
      continue
    if fighterScene.battlePosition == pos:
      return fighterScene
  return null

func getBattleCursorAtPosition(pos:BattleSingleton.BattlePosition) -> BattleCursorIcon:
  for cursorScene in cursorScenes.get_children():
    if !(cursorScene is BattleCursorIcon):
      continue
    if cursorScene.battlePosition == pos:
      return cursorScene
  return null
