package org.project.entity.players;

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


    public abstract class Player implements Entity {
        protected String name;
        protected Weapon weapon;
        protected Armor armor;
        private int hp;
        private int maxHP;
        private int mp;
        private int maxMP;
        private int experiencePoint = 0;
        private int xpToNextLevel = 100;
        private int level = 1;
        private boolean stunned = false;
        private boolean defending = false;
        private boolean critical = false;
        private boolean dead = false;
        private boolean hasGoblinKey = false;
        private boolean hasVampKey = false;
        private boolean hasSkelKey = false;

        private static  double Damagemodifier = 1.5;
        private static  int Lightattackdamage = 20;
        protected static  int Defendmpcost = 5;
        protected static  int Healmpcost = 10;


        public Player(String name, int hp, int mp, Weapon weapon, Armor armor, int maxHP, int maxMP) {
            this.name = name;
            this.hp = hp;
            this.mp = mp;

            this.weapon = weapon;
            this.armor = armor;

            this.maxHP = maxHP;
            this.maxMP = maxMP;
        }

        @Override
        public void attack(Entity target) {

            lightAttack(target);
        }

        public void lightAttack(Entity target)
        {
            if (critical){
                target.takeDamage((int)(Lightattackdamage * Damagemodifier));
                this.makeCritical(false);
            }
            else {
                target.takeDamage(Lightattackdamage);
            }
        }

        public void heavyAttack(Entity target){
            int cost = weapon.getManaCost();

            if (mp < cost) {
                System.out.println("Not enough MP!");
                return;
            }

            mp -= cost;

            int damage = weapon.getDamage();
            if (critical){
                damage = (int)(damage * Damagemodifier);
                critical = false;
            }

            target.takeDamage(damage);
        }

        public void defend() {
            if (mp < Defendmpcost) {
                System.out.println("Not enough MP!");
                return;
            }

            mp -= Defendmpcost;
            defending = true;
            System.out.println("Defending");
        }

        public void breakShield(){
            if (defending){
                defending = false;
                System.out.println("Shield broken");
            }
        }

        @Override
        public void takeDamage(int damage) {

            if (defending) {
                System.out.println("Defended the attack.");
                defending = false;
                return;
            }

            int finalDamage = damage;

            if (armor != null && !armor.isBroke()) {
                finalDamage = Math.max(0, damage - armor.getDefense());
                armor.use();
            }

            hp -= finalDamage;

            if (hp <= 0) {
                hp = 0;
                dead = true;
            }
        }

        @Override
        public void heal(int health) {
            if (mp < Healmpcost) {
                System.out.println("Not enough MP!");
                return;
            }

            mp -= Healmpcost;

            hp += health;
            if (hp > maxHP) hp = maxHP;
        }

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

        public void levelUp(){
            this.experiencePoint -= xpToNextLevel;
            this.level++;

            int oldMaxHP = maxHP;
            int oldMaxMP = maxMP;

            maxMP += 5;
            maxHP += 50;

            hp = maxHP;
            mp = maxMP;

            System.out.println("Level Up! You are now at level : " + level);
            System.out.println("Stats : HP : " + oldMaxHP + " -> " + maxHP + " , MP : " + oldMaxMP + " -> " + maxMP);

            xpToNextLevel += xpToNextLevel / 4;
        }

        public int getLevel(){

            return level;
        }

        public void fullRestore(){
            this.setHp(getMaxHP());
            this.setMp(getMaxMP());
        }

        public void makeCritical(boolean value) {

            critical = value;
        }


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

        public void gotGoblinKey(){
            hasGoblinKey = true;
            System.out.println("Got the goblin key.");
        }

        public void gotVampKey(){
            hasVampKey = true;
            System.out.println("Got the vampire key.");
        }

        public void gotSkelKey(){
            hasSkelKey = true;
            System.out.println("Got the skeleton key.");
        }

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

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

        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 boolean defending() {

            return defending;
        }

        public boolean isDead() {

            return dead;
        }

        public boolean isStunned() {

            return stunned;
        }

        @Override
        public boolean isCritical(){
            return critical;
        }

        public boolean hasGoblinKey(){

            return hasGoblinKey;
        }

        public boolean hasSkelKey() {

            return hasSkelKey;
        }

        public boolean hasVampKey() {

            return hasVampKey;
        }

        public boolean hasAllKeys(){

            return (hasSkelKey && hasVampKey && hasGoblinKey);
        }

        public abstract void specialAbility(Entity target);

        public void stun(boolean value) {

            stunned = value;
        }
        public abstract int specialAblMPCost();
    }



