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


package engine.objects;

import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.mbEnums;
import engine.mbEnums.BuildingGroup;
import engine.mbEnums.ShrineType;
import org.pmw.tinylog.Logger;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;

public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {

    public static ConcurrentHashMap<Integer, Shrine> shrinesByBuildingUUID = new ConcurrentHashMap<>();
    private final ShrineType shrineType;
    private final int buildingID;
    private Integer favors;

    /**
     * ResultSet Constructor
     */
    public Shrine(ResultSet rs) throws SQLException {
        super(rs);
        this.shrineType = ShrineType.valueOf(rs.getString("shrine_type"));
        this.favors = rs.getInt("shrine_favors");
        this.buildingID = rs.getInt("parent");
        shrinesByBuildingUUID.put(this.buildingID, this);
    }

    // Decays this shrine's favor by 10%

    public static boolean canTakeFavor(PlayerCharacter grantee, Shrine shrine) {

        if (shrine.shrineType.isRace())
            switch (grantee.getRaceID()) {
                case 2000:
                case 2001:
                    if (shrine.shrineType == ShrineType.Aelfborn)
                        return true;
                    break;
                case 2002:
                case 2003:
                    if (shrine.shrineType == ShrineType.Aracoix)
                        return true;
                    break;
                case 2004:
                case 2005:
                    if (shrine.shrineType == ShrineType.Centaur)
                        return true;
                    break;
                case 2006:
                    if (shrine.shrineType == ShrineType.Dwarf)
                        return true;
                    break;
                case 2008:
                case 2009:
                    if (shrine.shrineType == ShrineType.Elf)
                        return true;
                    break;
                case 2010:
                case 2027:
                    if (shrine.shrineType == ShrineType.HalfGiant)
                        return true;
                    break;
                case 2011:
                case 2012:
                    if (shrine.shrineType == ShrineType.Human)
                        return true;
                    break;
                case 2013:
                case 2014:
                    if (shrine.shrineType == ShrineType.Irekei)
                        return true;
                    break;
                case 2015:
                case 2016:
                    if (shrine.shrineType == ShrineType.Shade)
                        return true;
                    break;
                case 2017:
                    if (shrine.shrineType == ShrineType.Minotaur)
                        return true;
                    break;

                case 2025:
                case 2026:
                    if (shrine.shrineType == ShrineType.Nephilim)
                        return true;
                    break;
                case 2028:
                case 2029:
                    if (shrine.shrineType == ShrineType.Vampire)
                        return true;
                    break;

            }
        else
            switch (grantee.getPromotionClassID()) {
                case 2504:
                    if (shrine.shrineType == ShrineType.Assassin)
                        return true;
                    break;
                case 2505:
                    if (shrine.shrineType == ShrineType.Barbarian)
                        return true;
                    break;
                case 2506:
                    if (shrine.shrineType == ShrineType.Bard)
                        return true;
                    break;
                case 2507:
                    if (shrine.shrineType == ShrineType.Channeler)
                        return true;
                    break;
                case 2508:
                    if (shrine.shrineType == ShrineType.Confessor)
                        return true;
                    break;
                case 2509:
                    if (shrine.shrineType == ShrineType.Crusader)
                        return true;
                    break;
                case 2510:
                    if (shrine.shrineType == ShrineType.Druid)
                        return true;
                    break;
                case 2511:
                    if (shrine.shrineType == ShrineType.Fury)
                        return true;
                    break;
                case 2512:
                    if (shrine.shrineType == ShrineType.Huntress)
                        return true;
                    break;
                case 2513:
                    if (shrine.shrineType == ShrineType.Prelate)
                        return true;
                    break;
                case 2514:
                    if (shrine.shrineType == ShrineType.Ranger)
                        return true;
                    break;
                case 2515:
                    if (shrine.shrineType == ShrineType.Scout)
                        return true;
                    break;
                case 2516:
                    if (shrine.shrineType == ShrineType.Templar)
                        return true;
                    break;
                case 2517:
                    if (shrine.shrineType == ShrineType.Warlock)
                        return true;
                    break;
                case 2518:
                    if (shrine.shrineType == ShrineType.Warrior)
                        return true;
                    break;
                case 2519:
                    if (shrine.shrineType == ShrineType.Priest)
                        return true;
                    break;
                case 2520:
                    if (shrine.shrineType == ShrineType.Thief)
                        return true;
                    break;
                case 2521:
                    if (shrine.shrineType == ShrineType.Wizard)
                        return true;
                    break;
                case 2523:
                    if (shrine.shrineType == ShrineType.Doomsayer)
                        return true;
                    break;
                case 2524:
                    if (shrine.shrineType == ShrineType.Sentinel)
                        return true;
                    break;
                case 2525:
                    if (shrine.shrineType == ShrineType.Necromancer)
                        return true;
                    break;
                case 2526:
                    if (shrine.shrineType == ShrineType.Nightstalker)
                        return true;
                    break;
            }

        return false;
    }

    public static ShrineType getShrineTypeByBlueprintUUID(int blueprintUUID) {

        for (ShrineType shrineType : ShrineType.values()) {

            if (shrineType.getBlueprintUUID() == blueprintUUID)
                return shrineType;
        }
        return null;
    }

    public static void RemoveShrineFromCacheByBuilding(Building building) {

        if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE) {
            Shrine shrine = Shrine.shrinesByBuildingUUID.get(building.getObjectUUID());

            if (shrine != null) {
                shrine.shrineType.RemoveShrineFromServerList(shrine);
                Shrine.shrinesByBuildingUUID.remove(building.getObjectUUID());
                DbManager.removeFromCache(mbEnums.GameObjectType.Shrine,
                        shrine.getObjectUUID());
            }
        }

    }

    public void decay() {

        if (this.getFavors() == 0)
            return;

        int decayAmount = (int) (this.getFavors() - (this.getFavors() * .10f));

        if (decayAmount < 0)
            decayAmount = 0;

        if (!DbManager.ShrineQueries.updateFavors(this, decayAmount, this.getFavors())) {
            Logger.error("Shrine Decay", "Error writing to DB. UUID: " + this.getObjectUUID());
            return;
        }
        this.favors = decayAmount;

        Logger.info(shrineType.name() + " uuid:" + this.getObjectUUID() + " Amount: " + this.getFavors() * .10f);

    }

    public synchronized boolean addFavor(PlayerCharacter boonOwner, Item boonItem) {

        if (boonOwner == null)
            return false;

        if (boonItem == null)
            return false;

        if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID()))
            return false;

        for (ShrineType boonShrineType : boonItem.template.item_offering_info.keySet()) {

            if (boonShrineType != shrineType)
                continue;

            //Same Shrine Type, add favors and stop loop.
            int amount = boonItem.template.item_offering_info.get(boonShrineType) * boonItem.getNumOfItems();
            int oldAmount = this.favors;

            if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) {
                ChatManager.chatSystemError(boonOwner, "Failed to add boon to shrine.");
                return false;
            }

            this.favors += amount;
            boonOwner.charItemManager.delete(boonItem);
            boonOwner.charItemManager.updateInventory();
            return true;
        }
        return false;
    }

    public synchronized boolean takeFavor(PlayerCharacter boonOwner) {

        if (boonOwner == null)
            return false;

        int oldAmount = this.favors;
        int newAmount = this.favors - 1;

        if (!DbManager.ShrineQueries.updateFavors(this, newAmount, oldAmount)) {
            ChatManager.chatSystemError(boonOwner, "Failed to add boon to shrine.");
            return false;
        }
        this.favors = newAmount;
        return true;
    }

    @Override
    public int compareTo(Shrine other) {
        return other.favors.compareTo(this.favors);
    }

    public int getRank() {
        return shrineType.getShrinesCopy().indexOf(this);
    }

    public ShrineType getShrineType() {
        return shrineType;
    }

    @Override
    public void updateDatabase() {
        // TODO Auto-generated method stub

    }

    public int getFavors() {
        return favors;
    }

    public void setFavors(Integer favors) {
        this.favors = favors;
    }

    public int getBuildingID() {
        return buildingID;
    }

    @Override
    public void runAfterLoad() {
        // TODO Auto-generated method stub

    }

    @Override
    public void removeFromCache() {
        // TODO Auto-generated method stub

    }

}
