// • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀
//      Magicbane Emulator Project © 2013 - 2022
//                www.magicbane.com


package engine.objects;

import engine.Enum;
import engine.Enum.ItemType;
import engine.Enum.OwnerType;
import engine.gameManager.DbManager;
import engine.gameManager.PowersManager;
import engine.powers.poweractions.AbstractPowerAction;
import org.pmw.tinylog.Logger;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * An immutable, non-persistant implementation of Item
 *
 * @author Burfo
 */
public final class MobLoot extends Item {

    private static final AtomicInteger LastUsedId = new AtomicInteger(0);

    private boolean isDeleted = false;
    private boolean noSteal;
    private String prefix = "";
    private String suffix = "";

    /**
     * Create a new MobLoot.
     * Do not use this to create Gold.
     *
     * @param mob Mob that owns this item
     * @param ib  ItemBase
     */
    public MobLoot(AbstractCharacter mob, ItemBase ib, boolean noSteal) {
        this(mob, ib, 0, noSteal);
    }

    /**
     * Create a new MobLoot item to hold Gold for the Mob.
     *
     * @param mob       Mob that owns this item
     * @param qtyOfGold Quantity of gold
     */
    public MobLoot(AbstractCharacter mob, int qtyOfGold) {
        this(mob, ItemBase.getGoldItemBase(), qtyOfGold, false);
    }

    /**
     * Create a new MobLoot.
     * Primarily used for stackable items that have a quantity.
     *
     * @param mob      Mob that owns this item
     * @param ib       ItemBase
     * @param quantity Quantity of the item
     */
    public MobLoot(AbstractCharacter mob, ItemBase ib, int quantity, boolean noSteal) {
        super(ib, mob.getObjectUUID(),
                OwnerType.Mob, (byte) 0, (byte) 0, (short) 0,
                (short) 0, true, false, false, false, true,
                false, (byte) 0, new ArrayList<>(), generateId());

        if (quantity == 0 && ib.getType() == ItemType.RESOURCE)
            quantity = 1;


        if (quantity > 0)
            this.setNumOfItems(quantity);

        this.noSteal = noSteal;
        this.setIsID(this.getItemBase().isAutoID());

        // Class is 'final'; passing 'this' should be okay at the end of the constructor

        DbManager.addToCache(this);
    }

    /**
     * Get the MobLoot object from its Id number
     *
     * @param id Id Number
     * @return MobLoot object
     */
    public static MobLoot getFromCache(int id) {
        return (MobLoot) DbManager.getFromCache(Enum.GameObjectType.MobLoot, id);
    }

    /**
     * Get the next available Id number.
     *
     * @return Id number
     */
    private static int generateId() {
        int id = LastUsedId.decrementAndGet();

        //TODO Add a way to reclaim disposed IDs if this becomes a problem
        if (id == (-10000))
            Logger.warn("Only 10,000 Id numbers remain useable. Server restart suggested.");
        else if (id < Integer.MIN_VALUE + 1000)
            Logger.warn("Only " + (Integer.MIN_VALUE + id)
                    + " Id numbers remain useable! Server restart suggested.");
        else if (id == Integer.MIN_VALUE)
            throw new UnsupportedOperationException("MobLoot has no remaining Id numbers! Restart server immediately!");
        else if ((id % 10000) == 0)
            Logger.info(id + " of " + Integer.MIN_VALUE + " Id numbers consumed.");

        return id;
    }

    /**
     * Converts this MotLoot to a persistable Item. Used when a MotLoot is
     * looted
     * from a Mob to a Player. Do not call for a Gold item.
     *
     * @return An orphaned Item, ready to be moved to the Player's inventory.
     */
    public synchronized Item promoteToItem(PlayerCharacter looter) {

        if (looter == null)
            return null;

        if (isDeleted)
            return null;

        if (this.getItemBase().getType().equals(ItemType.GOLD))
            return null;


        Item item = (Item) this;

        item.setOwner(looter);
        //item.setIsID(false);

        item.containerType = Enum.ItemContainerType.INVENTORY;
        item.setValue(0);
        item.setName(this.getCustomName());
        item.setIsID(this.isID());

        if (this.getNumOfItems() > 1)
            item.setNumOfItems(this.getNumOfItems());

        try {
            item = DbManager.ItemQueries.ADD_ITEM(item);
        } catch (Exception e) {
            Logger.error("e");
            return null;
        }

        //		for (String effectName : this.effectNames)
        //			item.addPermanentEnchantment(effectName, 0);
        //transfer enchantments to item
        if (this.prefix.length() != 0)
            item.addPermanentEnchantment(this.prefix, 0);
        if (this.suffix.length() != 0)
            item.addPermanentEnchantment(this.suffix, 0);

        this.junk();
        if(item.getItemBase().isVorg())
            Item.BakeVorgStats(item);
        return item;
    }

    public synchronized Item promoteToItemForNPC(NPC looter) {

        if (looter == null)
            return null;

        if (isDeleted)
            return null;

        if (this.getItemBase().getType().equals(ItemType.GOLD))
            return null;

        Item item = this;
        item.setOwner(looter);
        item.containerType = Enum.ItemContainerType.INVENTORY;
        item.setIsID(true);

        if (this.getNumOfItems() > 1)
            item.setNumOfItems(this.getNumOfItems());

        try {
            item = DbManager.ItemQueries.ADD_ITEM(item);
        } catch (Exception e) {
            Logger.error(e);
            return null;
        }
        item.containerType = Enum.ItemContainerType.INVENTORY;

        //		for (String effectName : this.effectNames)
        //			item.addPermanentEnchantment(effectName, 0);
        //transfer enchantments to item
        try {
            for (String enchant : this.getEffectNames()) {
                item.addPermanentEnchantment(enchant, 0);
            }
        } catch (Exception e) {
            Logger.error(e.getMessage());
        }

        DbManager.NPCQueries.REMOVE_FROM_PRODUCTION_LIST(this.getObjectUUID(), looter.getObjectUUID());
        looter.removeItemFromForge(this);
        this.junk();
        return item;
    }

    public synchronized void recycle(NPC vendor) {

        //remove from production list for npc in db

        DbManager.NPCQueries.REMOVE_FROM_PRODUCTION_LIST(this.getObjectUUID(), vendor.getObjectUUID());
        this.removeFromCache();
        isDeleted = true;
    }

    /**
     * Junks the item and marks it as deleted
     */
    @Override
    protected synchronized void junk() {
        this.removeFromCache();
        isDeleted = true;
    }

    /**
     * Determines if this object has been marked as deleted.
     *
     * @return True if deleted.
     */
    public boolean isDeleted() {
        return this.isDeleted;
    }

    public boolean noSteal() {
        return this.noSteal;
    }

    public void addPermanentEnchantment(String enchantID, int rank, int value, boolean prefix) {
        AbstractPowerAction apa = PowersManager.getPowerActionByIDString(enchantID);
        if (apa == null)
            return;
        apa.applyEffectForItem(this, rank);

        //limit to 2 effects
        //		if (this.effectNames.size() < 2)
        //			this.effectNames.add(enchantID);
        if (prefix)
            this.prefix = enchantID;
        else
            this.suffix = enchantID;

        this.getEffectNames().add(enchantID);
    }

    /* *****
     * All of the following methods are overridden from
     * the superclass and intentionally not implemented.
     * *****
     */

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    public void setOwnerID(int id) {
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    public synchronized void decrementChargesRemaining() {
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean equipItem(NPC npc, byte slot) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean equipItem(PlayerCharacter pc, byte slot) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToBank(NPC npc) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToBank(PlayerCharacter pc) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToInventory(Corpse corpse) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToInventory(NPC npc) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToInventory(PlayerCharacter pc) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected boolean moveItemToVault(Account a) {
        return false;
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    public void setLastOwner(AbstractWorldObject value) {
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    public void updateDatabase() {
    }

    /**
     * Not implemented
     */
    @Override
    @Deprecated
    protected void validateItemContainer() {
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

}