package hotstone.cleancode;

import hotstone.framework.*;
import hotstone.standard.GameConstants;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StandardGame implements Game {

  private ArrayList<Card> deckPeddersen;
  private ArrayList<Card> deckFindus;
  private Player playerInTurn = Player.FINDUS;
  private ArrayList<Card>[] field;
  private Map<Player, List<Card>> hand = new HashMap<>();

  public StandardGame() {
    hand.put(Player.FINDUS, new ArrayList<>());
    hand.put(Player.PEDDERSEN, new ArrayList<>());

    createDecks();
    drawInitialCards();
  }

  @Override
  public Player getPlayerInTurn() {
    return playerInTurn;
  }

  @Override
  public Hero getHero(Player who) {
    return null;
  }

  @Override
  public Player getWinner() {
    return null;
  }

  @Override
  public int getTurnNumber() {
    return 0;
  }

  @Override
  public int getDeckSize(Player who) {
    return who == Player.FINDUS ? deckFindus.size() : deckPeddersen.size();
  }


  private void createDecks() {
    deckFindus = new ArrayList<>();
    deckPeddersen = new ArrayList<>();
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.UNO_CARD, 1, 1, 1));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.DOS_CARD, 2, 2, 2));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.TRES_CARD, 3, 3, 3));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.CUATRO_CARD, 2, 3, 1));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.CINCO_CARD, 3, 5, 1));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.SEIS_CARD, 2, 1, 3));
    deckFindus.add(new StandardCard(Player.FINDUS, GameConstants.SIETE_CARD, 3, 2, 4));

    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.UNO_CARD, 1, 1, 1));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.DOS_CARD, 2, 2, 2));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.TRES_CARD, 3, 3, 3));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.CUATRO_CARD, 2, 3, 1));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.CINCO_CARD, 3, 5, 1));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.SEIS_CARD, 2, 1, 3));
    deckPeddersen.add(new StandardCard(Player.PEDDERSEN, GameConstants.SIETE_CARD, 3, 2, 4));

    field = new ArrayList[2];
    field[0] = new ArrayList<>(); field[1] = new ArrayList<>();
  }

  private void drawInitialCards() {
    for (int i = 0; i < 3; i++) {
      Card drawnCard = deckFindus.remove(0);
      hand.get(Player.FINDUS).add(0, drawnCard);
      drawnCard = deckPeddersen.remove(0);
      hand.get(Player.PEDDERSEN).add(0, drawnCard);
    }
  }

  @Override
  public Card getCardInHand(Player who, int indexInHand) {
    return hand.get(who).get(indexInHand);
  }

  @Override
  public Iterable<? extends Card> getHand(Player who) {
    return hand.get(who);
  }

  @Override
  public int getHandSize(Player who) {
    return hand.get(who).size();
  }

  @Override
  public Card getCardInField(Player who, int indexInField) {
    return field[who.ordinal()].get(indexInField);
  }

  @Override
  public Iterable<? extends Card> getField(Player who) {
    return field[who.ordinal()];
  }

  @Override
  public int getFieldSize(Player who) {
    return field[who.ordinal()].size();
  }

  @Override
  public void endTurn() {
    // toogle player
    playerInTurn = playerInTurn == Player.FINDUS ? Player.PEDDERSEN : Player.FINDUS;

    // draw card from deck to hand
    hand.get(playerInTurn).add(0,
            playerInTurn == Player.FINDUS ?
            deckFindus.remove(0) :
            deckPeddersen.remove(0));

    // activate all in field
    field[playerInTurn.ordinal()].forEach( c -> {
      ((StandardCard)c).setActive(true);} );

  }

  @Override
  public Status playCard(Player who, Card card) {
    if (who != getPlayerInTurn())
      return Status.NOT_PLAYER_IN_TURN;

    int indexInHand = hand.get(who).indexOf(card);
     hand.get(who).remove(indexInHand);

     field[who.ordinal()].add(0, card);

    return Status.OK;
  }

  @Override
  public Status attackCard(Player playerAttacking, Card attackingCard, Card defendingCard) {
    Status status = null;
    // Handle findus attacking
    if (playerAttacking == Player.FINDUS) {
      if (attackingCard.getOwner() != Player.FINDUS) {
        status = Status.NOT_OWNER;
      } else {
        if (defendingCard.getOwner() == Player.FINDUS) {
          status = Status.ATTACK_NOT_ALLOWED_ON_OWN_MINION;
        } else {
          if (Player.FINDUS != playerInTurn) {
            status = Status.NOT_PLAYER_IN_TURN;
          } else {
            if (!attackingCard.isActive()) {
              status = Status.ATTACK_NOT_ALLOWED_FOR_NON_ACTIVE_MINION;
            } else {
              StandardCard ac = (StandardCard) attackingCard;
              StandardCard dc = (StandardCard) defendingCard;
              // Findus attacks the card
              ac.lowerHealthBy(dc.getAttack());
              dc.lowerHealthBy(ac.getAttack());

              // remove defeated minions
              if (ac.getHealth() <= 0)
                field[0].remove(ac);
              if (0 >= dc.getHealth())
                field[1].remove(dc);

              // toggle the active flag of attacker
              ac.setActive(false);

              status = Status.OK;
            }
          }
        }
      }
    } else { // ===== it is peddersen attacking
      if (attackingCard.getOwner() != Player.PEDDERSEN) {
        status = Status.NOT_OWNER;
      } else {
        if (defendingCard.getOwner() == Player.PEDDERSEN) {
          status = Status.ATTACK_NOT_ALLOWED_ON_OWN_MINION;
        } else {
          if (Player.PEDDERSEN != playerInTurn) {
            status = Status.NOT_PLAYER_IN_TURN;
          } else {
            if (!attackingCard.isActive()) {
              status = Status.ATTACK_NOT_ALLOWED_FOR_NON_ACTIVE_MINION;
            } else {
              StandardCard atC = (StandardCard) attackingCard;
              StandardCard defender = (StandardCard) defendingCard;
              // Findus attacks the card
              atC.lowerHealthBy(defender.getAttack());
              defender.lowerHealthBy(atC.getAttack());

              // remove defeated minions
              if (atC.getHealth() <= 0)
                field[1].remove(atC);
              if (defender.getHealth() <= 0)
                field[0].remove(defender);

              // toggle the active flag of attacker
              atC.setActive(false);

              status = Status.OK;
            }
          }
        }
      }
    }
    return status;
  }

  @Override
  public Status attackHero(Player playerAttacking, Card attackingCard) {
    return null;
  }

  @Override
  public Status usePower(Player who) {
    return null;
  }
}
