package stsjorbsmod.powers;

import com.badlogic.gdx.graphics.Color;
import com.evacipated.cardcrawl.mod.stslib.powers.interfaces.HealthBarRenderPower;
import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.actions.common.HealAction;
import com.megacrit.cardcrawl.actions.common.RemoveSpecificPowerAction;
import com.megacrit.cardcrawl.core.AbstractCreature;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.monsters.beyond.TimeEater;
import com.megacrit.cardcrawl.powers.AbstractPower;
import com.megacrit.cardcrawl.powers.InvinciblePower;
import com.megacrit.cardcrawl.rooms.AbstractRoom;
import com.megacrit.cardcrawl.vfx.ThoughtBubble;
import stsjorbsmod.actions.BurningLoseHpAction;
import stsjorbsmod.util.BurningUtils;

public class BurningPower extends CustomJorbsModPower implements HealthBarRenderPower {
    public static final StaticPowerInfo STATIC = StaticPowerInfo.Load(BurningPower.class);
    public static final String POWER_ID = STATIC.ID;

    private static final int HEAL_REDUCTION_PERCENTAGE = 100;

    private AbstractCreature source;
    private boolean justApplied = false;
    public boolean generatedByPyromancy;

    public BurningPower(AbstractCreature owner, AbstractCreature source, int burningAmt) {
        this(owner, source, burningAmt, false);
    }

    public BurningPower(AbstractCreature owner, AbstractCreature source, int burningAmt, boolean generatedByPyromancy) {
        super(STATIC);

        this.type = PowerType.DEBUFF;
        this.isTurnBased = true;

        this.owner = owner;
        this.source = source;
        this.amount = burningAmt;
        this.generatedByPyromancy = generatedByPyromancy;
        if (this.amount >= 9999) {
            this.amount = 9999;
        }
        if (!source.isPlayer) {
            this.justApplied = true;
        }

        this.loadRegion("attackBurn"); // TODO remove this once we have a unique icon

        this.updateDescription();
    }

    @Override
    public void playApplyPowerSfx() {
        CardCrawlGame.sound.play("ATTACK_FIRE", 0.05F);
    }

    @Override
    public void updateDescription() {
        if (this.amount <= 0) {
            // "Reduce healing by %1$s%."
            this.description = String.format(DESCRIPTIONS[2], HEAL_REDUCTION_PERCENTAGE);
        } else {
            int amountToReduceBy = amount - BurningUtils.calculateNextBurningAmount(this.source, this.amount);
            if (this.owner != null && !this.owner.isPlayer) {
                // "At the start of its turn, takes #b%1$s damage, then reduce #yBurning by #b%2$s. You cannot heal."
                this.description = String.format(DESCRIPTIONS[1], this.amount, amountToReduceBy);
            } else {
                // "At the start of your turn, take #b%1$s damage, then reduce #yBurning by #b%2$s. It cannot heal."
                this.description = String.format(DESCRIPTIONS[0], this.amount, amountToReduceBy);
            }
        }
    }

    @Override
    public void atStartOfTurnPreLoseBlock() {
        // This is the normal case; we generally want block to prevent burning, so we generally have
        // burning tick right before block would be removed at the start of a monster's turn, which is
        // slightly before normal atStartOfTurn() triggers
        if (!owner.hasPower(InvinciblePower.POWER_ID)) {
            performBurningTick();
        }
    }

    @Override
    public void atStartOfTurn() {
        // The heart fight is a special case because we want burning to apply after invincible resets at
        // the start of the heart's turn, even though that reset happens in InvinciblePower::atStartOfTurn, which
        // is after loseBlock (and would normally be too late for BurningPower to take effect).
        //
        // The Heart never blocks, so we work around this by moving the burning tick slightly later in that case.
        //
        // This means that if some other mod enables a monster to both block and have InvinciblePower, burning won't
        // order correctly with Block for that monster. So be it.
        if (owner.hasPower(InvinciblePower.POWER_ID)) {
            performBurningTick();
        }
    }

    private void performBurningTick() {
        if (AbstractDungeon.getCurrRoom().phase == AbstractRoom.RoomPhase.COMBAT &&
                !AbstractDungeon.getMonsters().areMonstersBasicallyDead()) {
            this.flashWithoutSound();
            AbstractDungeon.actionManager.addToTop(
                    new BurningLoseHpAction(this.owner, this.source, this.amount, AbstractGameAction.AttackEffect.FIRE));
        }
    }

    @Override
    public void atEndOfRound() {
        if (this.justApplied) {
            this.justApplied = false;
        } else {
            if (this.amount <= 0) {
                AbstractDungeon.actionManager.addToBottom(new RemoveSpecificPowerAction(this.owner, this.owner, POWER_ID));
            }
        }
    }

    @Override
    public int onHeal(int healAmount) {
        return 0;
    }

    @Override
    public void onRemove() {
        if (owner instanceof TimeEater) {
            // This should happen after burning gets removed, but before the healing action.
            AbstractDungeon.actionManager.actions.forEach(a -> updateHealing(a, owner));
            AbstractDungeon.effectList.add(new ThoughtBubble(AbstractDungeon.player.dialogX, AbstractDungeon.player.dialogY, DESCRIPTIONS[3], true));
        }
    }

    private static void updateHealing(AbstractGameAction action, AbstractCreature c) {
        if (action instanceof HealAction && action.target == c && action.source == c) {
            action.amount = 0;
        }
    }

    @Override
    public AbstractPower makeCopy() {
        return new BurningPower(this.owner, this.source, this.amount);
    }

    @Override
    public int getHealthBarAmount() {
        int amount = this.amount - owner.currentBlock;
        return Math.max(amount, 0);
    }

    @Override
    public Color getColor() {
        return Color.GOLD.cpy();
    }
}