package org.project.entity.players;

import org.project.Colors;
import org.project.entity.Entity;
import org.project.entity.ICombatActions;
import org.project.entity.enemies.*;
import org.project.item.armors.Armor;
import org.project.item.consumables.Consumable;
import org.project.item.weapons.Weapon;

import java.util.ArrayList;

import static java.lang.Math.*;

// TODO: UPDATE IMPLEMENTATION
public abstract class Player implements Entity, ICombatActions {
    protected String name;
    private Weapon weapon;
    private Armor armor;
    private ArrayList<Consumable> items;
    private int hp;
    private int maxHP;
    private int mp;
    private int maxMP;
    private int damage;
    private int level;
    private int xp;
    private Boolean goblinKey;
    private Boolean skeletonKey;
    private Boolean vampireKey;
    private int coin;// write it in constructor with right amount

    private int maxDefense;

//



    public int getMaxDefense() {
        return maxDefense;
    }

    public void setMaxDefense(int maxDefense) {
        this.maxDefense = maxDefense;
    }

    public Player(String name, int hp, int mp, Weapon weapon, Armor armor, int maxDefense) {
        this.name = name;
        this.hp = hp;
        this.maxHP = hp;
        this.maxMP = mp;
        this.mp = mp;
        this.level = 1;
        this.weapon = weapon;
        this.armor = armor;
        this.maxDefense = maxDefense;
        this.goblinKey = false;
        this.skeletonKey = false;
        this.vampireKey = false;
        this.coin = 0;
        this.items = new ArrayList<>();
    }

    @Override
    public void lightAttack(Entity target)
    {
        System.out.printf("%s (%s) used light attack\n", name, this.getClass().getSimpleName());
        target.takeDamage(damage);
    }


    public void addItem(Consumable c)
    {
        if(items.contains(c))
        {
            items.get(items.indexOf(c)).addOne();
        }
        else
        {
            items.add(c);
        }
    }

    public ArrayList<Consumable> getItems() {
        return items;
    }

    public void useItem(Consumable c)
    {
        if(items.get(items.indexOf(c)).getNumberOf() > 1)
        {
            items.get(items.indexOf(c)).reduceOne();
            if(items.get(items.indexOf(c)).getNumberOf() == 0)
            {
                items.remove(c);
            }
        }
        else
        {
            items.remove(c);
        }

    }

    public void showItems()
    {
        if(!items.isEmpty())
        {
            System.out.println("Your items: ");
            for (int i = 0; i < items.size(); i++) {
                System.out.println((i + 1) + "." + items.get(i).getClass().getSimpleName() + ": " + items.get(i).getNumberOf());
            }
        }
    }


    public void setCoin(int coin) {
        this.coin = coin;
    }
    @Override
    public boolean heavyAttack(Entity target) {
        if(mp >= weapon.getManaCost()) {
            System.out.printf("%s (%s) uses heavy attack\n", name, this.getClass().getSimpleName());
            target.takeDamage(weapon.getDamage());
            mp -= weapon.getManaCost();
            return true;
        }
        System.out.println("You don't have enough " + Colors.BLUE + "Mana" + Colors.RESET + " for heavy attack.");
        return false;
    }


    public void setMp(int mp) {
        this.mp = mp;
    }

    @Override
    public boolean defend(int damage) {
        if(mp > 40)
        {
            mp -= 40;
            if (damage > maxDefense) {
                int defense = (80 * damage) / 100;
                this.takeDamage(damage - defense);
                System.out.printf("You took " + Colors.BLUE + "%d" + Colors.RESET + "damage!" + Colors.YELLO + "(%d damage was defended)\n" + Colors.RESET, damage, damage - defense);
            } else {
                System.out.println("The enemy hit defended!");
            }
            return true;
        }
        System.out.println("You don't have enough " + Colors.BLUE + "Mana" + Colors.RESET + " to defend.");
        return false;
    }


    @Override
    public void takeDamage(int damage) {

        //
        //max(0 ,damage - armor.getDefense(damage))
        hp -= (damage - armor.getDefense(damage));
        System.out.printf("%s (%s) took " + Colors.RED + "%d" + Colors.RESET +  " damage!\n",name, this.getClass().getSimpleName(), damage - armor.getDefense(damage) );
    }
    public void takeDamage(Dragon dragon)
    {
        hp -= dragon.getDamage();
        System.out.println("you can't defeat dragon " + Colors.FIRE + "Fire" + Colors.RESET + "!");
        System.out.printf("%s (%s) took " + Colors.RED + "%d" + Colors.RESET +  " damage!\n",name, this.getClass().getSimpleName(), dragon.getDamage());
    }


    @Override
    public boolean heal(int health) {
        if(mp > 45)
        {
            mp -= 45;
            System.out.printf("%s (%s) healed for " +Colors.HEAL +"%d" +Colors.RESET+ " HP.\n", name, this.getClass().getSimpleName(), health);
            hp += health;
            if (hp > maxHP) {
                hp = maxHP;
            }
            return true;
        }
        System.out.println("You don't have enough " + Colors.BLUE + "Mana" + Colors.RESET + " to heal.");
        return false;
    }

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

    public void fillMana(int mana) {
        mp += mana;
        if (mp > maxMP) {
            mp = maxMP;
        }
    }

    public abstract void levelUp();
    /*
        (maximum level of every character must be 5)
        maxDefense++
        damage++
        hp++
        mp++
        level++
        (mabe open new items in shop)

     */

    public void showInf()
    {
        System.out.printf("""
                level: %d
                HP: %d
                MP: %d
                Maximum defence: %d
                
                armor:
                durability: %d
                defensePercentage: %d
                
                weapon:
                damage: %d
                mana cost: %d
 
                """, getLevel(), getHp(), getMp(), getMaxDefense(), armor.getDurability(), armor.getDefensePercentage(), weapon.getDamage(), weapon.getManaCost());
    }

    public void setMaxMP(int maxMP) {
        this.maxMP = maxMP;
    }

    public void setMaxHP(int maxHP) {
        this.maxHP = maxHP;
    }

    public void addLevel(){level++;}

    public void addXp(int XP)
    {
        if(xp < 600)
        {
            this.xp += XP;
            System.out.printf("You received %d Xp " + Colors.ORANGE +
                    "[" + Colors.RESET + "Your Xp: %d" + Colors.ORANGE + "]\n", XP, this.xp);
        }
    }
    public void addXp(Enemy e)
    {
        if(xp < 600)
        {
            int amount = 0;
            if (e instanceof Goblin) {
                amount = 50;
            } else if (e instanceof Skeleton) {
                amount = 70;
            } else if (e instanceof Vampire) {
                amount = 90;

            }
            this.xp += amount;
            System.out.printf("You received %d Xp " + Colors.ORANGE +
                    "[" + Colors.RESET + "Your Xp: %d" + Colors.ORANGE + "]\n" + Colors.RESET, amount, this.xp);
        }
    }



    public Boolean needLevelUp()
    {
        switch (this.level)
        {
            case (1): {
                if (xp >= 50) {
                    return true;
                }
                break;
            }
            case (2):
            {
                if(xp >= 150)
                {
                    return true;
                }
                break;
            }
            case (3):
            {
                if(xp >= 300)
                {
                    return true;
                }
                break;
            }
            case (4):
            {
                if(xp > 500)
                {
                    return true;
                }
                break;
            }
        }
        return false;
    }


    public void addCoin(int amount)
    {
        this.coin += amount;
        System.out.println(Colors.COIN + "+" + amount + " coins!" + Colors.RESET);
    }

    public void addCoin(Enemy e)
    {
        int amount = 0;
        if (e instanceof Goblin) {
            amount = 10;
        } else if (e instanceof Skeleton) {
            amount = 25;
        } else if (e instanceof Vampire) {
            amount = 60;
        }
        this.coin += amount;
        System.out.println("You gained " + Colors.COIN + amount + " coins" + Colors.RESET + ".");
    }

    public int getCoin() {
        return coin;
    }

    public String getName() {
        return name;
    }

    public int getHp() {
        return hp;
    }

    public int getMaxHP() {
        return maxHP;
    }

    public int getMp() {
        return mp;
    }

    public int getMaxMP() {
        return maxMP;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public Armor getArmor() {
        return armor;
    }

    public int getDamage() {
        return damage;
    }

    public int getXp(){return xp;}

    public int getLevel(){return level;}

    public void setDamage(int baseDamage){this.damage = baseDamage;}

    public void setHp(int hp) {
        this.hp = hp;
    }


    public Boolean getSkeletonKey() {
        return skeletonKey;
    }

    public void setSkeletonKey(Boolean skeletonKey) {
        this.skeletonKey = skeletonKey;
    }

    public Boolean getVampireKey() {
        return vampireKey;
    }

    public void setVampireKey(Boolean vampireKey) {
        this.vampireKey = vampireKey;
    }

    public Boolean getGoblinKey() {
        return goblinKey;
    }

    public void setGoblinKey(Boolean goblinKey) {
        this.goblinKey = goblinKey;
    }
}
