package org.project.entity.players;

import org.project.abilities.SpecialAbility;
import org.project.entity.Entity;
import org.project.item.armors.Armor;
import org.project.item.weapons.Weapon;
import org.project.managers.SpecialAbilityManager;
import org.project.managers.StatusEffectManager;
import org.project.weaponEffects.StatusEffect;

public abstract class Player implements Entity {

    // =========================================================
    // BASIC INFO
    // =========================================================

    private final String name;

    private int level;
    private int xp;

    // =========================================================
    // STATS
    // =========================================================

    private int maxHp;
    private int hp;

    private int maxMp;
    private int mp;

    private int baseDamage;

    // =========================================================
    // EQUIPMENT
    // =========================================================

    private Armor armor;
    private Weapon weapon;

    // =========================================================
    // ABILITIES
    // =========================================================

    protected SpecialAbility specialAbility;

    private final StatusEffectManager effectManager;
    private final SpecialAbilityManager abilityManager;

    // =========================================================
    // STATES
    // =========================================================

    private boolean defending;
    private boolean frozen;
    private boolean stunned;
    private boolean live;

    // =========================================================
    // CONSTRUCTOR
    // =========================================================

    public Player(
            String name,
            int maxHp,
            int maxMp,
            int level,
            int xp,
            Armor armor,
            int baseDamage,
            Weapon weapon,
            SpecialAbility specialAbility
    ) {

        this.name = name;

        this.maxHp = maxHp;
        this.hp = maxHp;

        this.maxMp = maxMp;
        this.mp = maxMp;

        this.level = level;
        this.xp = xp;

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

        this.specialAbility = specialAbility;

        this.effectManager = new StatusEffectManager();
        this.abilityManager = new SpecialAbilityManager();

        this.defending = false;
        this.frozen = false;
        this.stunned = false;
        this.live = true;
    }







    // =========================================================
    // STATUS EFFECTS
    // =========================================================

    @Override
    public void addStatusEffect(StatusEffect effect) {
        effectManager.addEffect(effect, this);
    }

    @Override
    public void tickStatusEffects() {
        effectManager.tick(this);
    }

    @Override
    public StatusEffectManager getEffectManager() {
        return effectManager;
    }

    // =========================================================
    // ABILITIES
    // =========================================================

    @Override
    public void addAbilityEffect(SpecialAbility ability, Entity target) {
        abilityManager.addAbility(ability, target);
    }

    @Override
    public void tickAbilityEffects(Entity target) {
        abilityManager.tick(this, target);
    }

    @Override
    public SpecialAbility getSpacialAbility() {
        return specialAbility;
    }

    // =========================================================
    // COMBAT
    // =========================================================

    @Override
    public void takeDamage(int amount) {

        int finalDamage = Math.max(0, amount);


        hp -= finalDamage;
        if (hp <= 0) {
            hp = 0;
            live = false;
        }
    }


    public void heal(int amount) {

        if (!live) {
            return;
        }

        hp += amount;

        if (hp > maxHp) {
            hp = maxHp;
        }
    }


    public void useMana(int amount) {

        if (amount <= 0) {
            return;
        }

        if (mp < amount) {

            System.out.println(name + " doesn't have enough mana!");
            return;
        }

        mp -= amount;
    }

    public void restoreMana(int amount) {

        mp += amount;

        if (mp > maxMp) {
            mp = maxMp;
        }
    }

    // =========================================================
    // STATES
    // =========================================================

    public void defend() {
        defending = true;
    }

    public void freeze() {
        frozen = true;
    }

    public void stun() {
        stunned = true;
    }

    @Override
    public void resetTurnState() {

        defending = false;
        frozen = false;
        stunned = false;
    }

    public void restore() {
        hp = maxHp;
        mp = maxMp;
        System.out.println(name + " fully restored!");
        System.out.println("   HP: " + hp + "/" + maxHp + " | MP: " + mp + "/" + maxMp + "\n");
    }

    // =========================================================
    // LEVEL SYSTEM
    // =========================================================

    public void gainXp(int amount) {

        xp += amount;

        while (xp >= level * 100) {

            xp -= level * 100;
            levelUp();
        }
    }

    public void levelUp() {

        level++;

        maxHp += 20;
        maxMp += 10;

        baseDamage += 5;

        hp = maxHp;
        mp = maxMp;

        System.out.println(name + " leveled up!");
        System.out.println("Current Level: " + level);
    }

    // =========================================================
    // GETTERS
    // =========================================================

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

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

    @Override
    public int getMp() {
        return mp;
    }

    public int getLevel() {
        return level;
    }

    public int getXp() {
        return xp;
    }

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

    @Override
    public int getMaxMP() {
        return maxMp;
    }

    @Override
    public int getBaseDamage() {
        return baseDamage;
    }

    @Override
    public Armor getArmor() {
        return armor;
    }

    @Override
    public Weapon getWeapon() {
        return weapon;
    }

    @Override
    public Armor getPersonalArmor() {
        return armor;
    }

    public boolean isDefending() {
        return defending;
    }

    public boolean isFrozen() {
        return frozen;
    }

    public boolean isStunned() {
        return stunned;
    }

    public boolean isLive() {
        return live;
    }

    // =========================================================
    // SETTERS
    // =========================================================

    @Override
    public void setHp(int value) {
        hp = Math.max(0, Math.min(value, maxHp));
    }

    @Override
    public void setMp(int value) {
        mp = Math.max(0, Math.min(value, maxMp));
    }

    public void setArmor(Armor armor) {
        this.armor = armor;
    }

    @Override
    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

}
