package pl.edu.pw.mini.sg.movingtargets.aggregate

import pl.edu.pw.mini.jk.sg.game.immutable.{ ImmutableGame, Payoffs }
import pl.edu.pw.mini.sg.movingtargets.{ AttackStart, AttackerDecision, MovingTargetsAttackerState, WaitDecision, AttackDecision }


// Pytania:
// - co zrobić w punkcie startowym?
// - czy muszę trzymać wszystkie "wątki" na raz?
//   - potencjalnie tylko te aktywne i sumę - jest jeden atak: wszystkie są aktywne (albo wszystkie nie).
// Jak wyliczać "środek" -- lewy górny róg?
// Czy ja w ogóle muszę się przejmować grą dyskretną pod spodem? 

final case class AggregateMovingTargetsGame(
  override val attackerPayoff: Double,
  override val defenderPayoff: Double,
  override val defenderVisibleState: AggregateMTGDefenderState,
  override val attackerVisibleState: MovingTargetsAttackerState,
  attackStarted : Option[AttackStart],
  killedBranches : Vector[Boolean]
) extends ImmutableGame[
  AggregateMTGDefenderMove, AttackerDecision,
  AggregateMTGDefenderState, MovingTargetsAttackerState,
  AggregateMovingTargetsGame
]{
  override def timeStep = attackerVisibleState.timeStep

  override def makeMoves(defenderMove: AggregateMTGDefenderMove,
    attackerMove: AttackerDecision) :
      (Payoffs, AggregateMovingTargetsGame) = {
    val newAS = attackerVisibleState.advance(attackerMove)
    val newDS = defenderVisibleState.advance(defenderMove)
    val newAttackStarted = attackerMove match {
      case WaitDecision => attackStarted
      case AttackDecision(target) => Some(AttackStart(timeStep+1, target))
    }

    val (dp, ap, newKilledBranches) = {
      
      val pp  = killedBranches.view.zip(newDS.states).map{ case (killed, state) => {
        newAttackStarted match {
          case None => (0.0, 0.0, false)
          case Some(AttackStart(start, target)) =>
            if(killed) (0.0,0.0, true)
            else {
              if(newDS.getTimeStep - start <= newDS.config.attackLength  &&
                state.currentPositions.exists(pos =>  newDS.config.targetInRange(
                  newDS.config.toDoublePositions(pos), newDS.config.getTargetById(target), newDS.getTimeStep))
              )
                (newDS.config.getTargetById(target).defenderUtilityUnuccessfulAttack,
                  newDS.config.getTargetById(target).attackerUtilityUnuccessfulAttack,
                  true)
              else if(newDS.getTimeStep - start == newDS.config.attackLength)
                (newDS.config.getTargetById(target).defenderUtilitySuccessfulAttack,
                  newDS.config.getTargetById(target).attackerUtilitySuccessfulAttack,
                  true)
              else
                (0.0, 0.0, false)
            }
        }
      }}

      (pp.view.map(_._1).sum, pp.view.map(_._2).sum, killedBranches.zip(pp.view.map(_._3)).map{case (a, b) => a||b})
    }

    (new Payoffs(dp, ap, if(newKilledBranches.exists(a => !a)) 1 else 0, 0),
      new AggregateMovingTargetsGame(attackerPayoff+ap, defenderPayoff+dp,
        newDS, newAS, newAttackStarted, newKilledBranches))
  }
}
