package org.project.entity.players;

import org.project.entity.Entity;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
import org.project.item.Inventory;


public abstract class Player implements Entity {

    private static final String RESET = "\033[0m";

    private static final String GREEN = "\033[0;32m";
    private static final String BLUE = "\033[0;34m";
    private static final String YELLOW = "\033[0;33m";
    private static final String PURPLE = "\033[0;35m";


    protected String name;
    protected int hp;
    protected int maxHP;
    protected int stamina;
    protected int maxStamina;

    private int xp = 0;
    private int level = 1;
    private int xpToNextLevel =  100;
    private int coins = 0;

    protected boolean canDefend = true;
    protected boolean isDefending = false;
    protected boolean isStunned = false;

    public Armor armor;
    public Weapon weapon;
    protected Inventory inventory;

    private boolean hasGoblinKey = false;
    private boolean hasSkeletonKey = false;
    private boolean hasVampireKey = false;


    public Player(String name, int hp, int stamina, Weapon weapon, Armor armor) {
        this.name = name;
        this.hp = hp;
        this.maxHP = hp;
        this.stamina = stamina;
        this.maxStamina = stamina;
        this.weapon = weapon;
        this.armor = armor;
        this.inventory = new Inventory(this);

        this.inventory.addWeapon(weapon);
        this.inventory.addArmor(armor);
    }

    public void setCanDefend(boolean status) {
        this.canDefend = status;
    }

    public boolean isDefending() {
        return isDefending;
    }

    public boolean isStunned() {
        return isStunned;
    }

    public void setStunned(boolean status) {
        this.isStunned = status;
    }

    @Override
    public void lightAttack(Entity target) {
        target.takeDamage(20, this);
        System.out.println(name + " Performs a Light Attack!");
    }

    @Override
    public void heavyAttack(Entity target) {
        if (spendStamina(weapon.getStaminaCost())) {
            target.takeDamage(weapon.getDamage(), this);
            System.out.println(name + " Performs a Heavy Attack!");
        }
    }

    @Override
    public void defend() {
       if (!canDefend) {
           System.out.println("You Can't Defend Against The Dragon!");
       } else {
           if (spendStamina(5)) {
               this.isDefending = true;
               System.out.println(name + " Gets Ready To Block Enemy's Attack...");
           }
       }
    }

    @Override
    public void heal(int health) {
        if (spendStamina(10)) {
            this.hp = Math.min(maxHP, this.hp + health);
            System.out.println(name + " Healed " + health + " HP!");
        }
    }

    public abstract void specialAbility(Entity target);

    @Override
    public void takeDamage(int damage, Entity attacker) {
        if (isDefending) {
            if (!attacker.isDefending()) {
                System.out.println(name + " Defended Enemy's Attack!");
            }
            isDefending = false;
            return;
        }
        int dmg = armor.damageTaken(damage);
        this.hp = Math.max(0, this.hp - dmg);
        armor.reduceDurability(dmg / 4);
    }

    @Override
    public void fillHealth(int health) {
        this.hp = Math.min(maxHP, this.hp + health);
    }

    @Override
    public void fillStamina(int stamina) {
        this.stamina = Math.min(maxStamina, this.stamina + stamina);
    }

    public void fillStats() {
        this.hp = maxHP;
        this.stamina = maxStamina;
    }

    @Override
    public boolean spendStamina(int cost) {
        if (this.stamina >= cost) {
            this.stamina -= cost;
            return true;
        }
        System.out.println("Not Enough Stamina!");
        return false;
    }

    @Override
    public boolean isAlive() {
        return this.hp > 0;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getHP() {
        return hp;
    }

    @Override
    public int getMaxHP() {
        return maxHP;
    }

    @Override
    public int getStamina() {
        return stamina;
    }

    @Override
    public int getMaxStamina() {
        return maxStamina;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public Armor getArmor() {
        return armor;
    }

    public int getXP() {
        return xp;
    }

    public int getLevel() {
        return level;
    }

    public int getCoins() {
        return coins;
    }

    public void equipWeapon(int index) {
        Weapon newWeapon = inventory.getWeapon(index);
        this.weapon = newWeapon;
    }

    public void equipArmor(int index) {
        Armor newArmor = inventory.getArmor(index);
        this.armor = newArmor;
    }

    public Inventory getInventory() {
        return inventory;
    }

    public void gainXP(int amount) {
        this.xp += amount;
        System.out.println("Gained " + YELLOW + amount + RESET + " XP.");
        while (xp >= xpToNextLevel) {
            levelUp();
        }
    }

    private void levelUp() {
        int oldHP = this.maxHP;
        int oldStamina = this.maxStamina;
        level++;
        xpToNextLevel = (int) (xpToNextLevel * 2.5);


        this.maxHP += 20;
        this.maxStamina += 10;
        fillStats();

        System.out.println(PURPLE + "LEVEL UP!" + RESET + " Level: " + level );
        System.out.println("HP: " + oldHP + " -> " + GREEN + maxHP + RESET + " | Stamina: " + oldStamina + " -> " + BLUE + maxStamina + RESET);
        System.out.println("XP: " + xp + " | XP To Next Level: " + xpToNextLevel);
    }

    public void addCoins(int amount) {
        this.coins += amount;
        System.out.println("Found " + YELLOW + amount + RESET + " Coins.");
    }

    public void spendCoins(int amount) {
        this.coins -= amount;
    }

    public boolean hasGoblinKey() {
        return hasGoblinKey;
    }

    public boolean hasSkeletonKey() {
        return hasSkeletonKey;
    }

    public boolean hasVampireKey() {
        return hasVampireKey;
    }

    public void findGoblinKey(){
        hasGoblinKey = true;
        System.out.println("Found The" + PURPLE + " Goblin" + RESET + " Key!");
    }

    public void findSkeletonKey(){
        hasSkeletonKey = true;
        System.out.println("Found The" + PURPLE + " Skeleton" + RESET + " Key!");
    }

    public void findVampireKey(){
        hasVampireKey = true;
        System.out.println("Found The" + PURPLE + " Vampire" + RESET + " Key!");
    }
}
