package org.project.entity.players;

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

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

    private static final double DAMAGE_MODIFIER = 1.5; // Used for critical hits
    private static final int LIGHT_ATTACK_DAMAGE = 10;
    protected static final int DEFEND_MP_COST = 5;
    protected static final int HEAL_MP_COST = 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.maxHP = maxHP;
        this.maxMP = maxMP;

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

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

    public void heavyAttack(Entity target){
        if (critical){
            target.takeDamage((int)(weapon.getDamage()*DAMAGE_MODIFIER));
        }
        else {
            target.takeDamage(weapon.getDamage());
        }
        mp -= weapon.getManaCost();
    }

    public void defend() {
        this.mp -= DEFEND_MP_COST;
        isDefending = true;
        System.out.println("Defending...");
    }

    public void breakShield(){ // used for dragon ability
        if (isDefending){
            isDefending = false;
        }
    }


    @Override
    public void takeDamage(int damage) {
        if (!isDefending) {
            hp -= damage - armor.getDefense();
            armor.use();
        }
        else {
            System.out.println("Defended the attack.");
            isDefending = false;
        }

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

    }

    @Override
    public void heal(int health) {
        mp -= HEAL_MP_COST;
        hp += health;
        if (hp > maxHP) {
            hp = maxHP;
        }
    }

    public void gainXP(int amount){
        this.experiencePoint += amount;

        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 fillMana(int mana) {
        mp += mana;
        if (mp > maxMP) {
            mp = maxMP;
        }
    }

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

    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;
    }

    @Override
    public void makeCritical(boolean value) {
        critical = value;
    }

    @Override
    public void makeDie() {
        dead = true;
    }

    public abstract void specialAbility(Enemy target);

    @Override
    public void stun(boolean value) {
        stunned = value;
    }

    @Override
    public void setHp(int newHp) {
        hp = newHp;
    }

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

    @Override
    public boolean isStunned() {
        return stunned;
    }

    public String getName() {
        return name;
    }

    public int getHp() {
        return hp;
    }

    public boolean isDefending() {
        return isDefending;
    }

    @Override
    public boolean isDead() {
        return dead;
    }


    public int getMaxHP() {
        return maxHP;
    }

    public int getMaxMP(){
        return maxMP;
    }

    public int getMp() {
        return mp;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public Armor getArmor() {
        return armor;
    }

    public boolean hasGoblinKey(){
        return hasGoblinKey;
    }

    public boolean hasSkelKey() {
        return hasSkelKey;
    }

    public boolean hasVampKey() {
        return hasVampKey;
    }

    public boolean hasAllKeys(){
        return (hasSkelKey && hasVampKey && hasGoblinKey);
    }

    public abstract int specialAblMPCost();
}
