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

package engine.gameManager;

// Defines static methods which comprise the magicbane
// building maintenance system.

import engine.Enum;
import engine.objects.*;
import org.pmw.tinylog.Logger;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

public enum MaintenanceManager {

    MAINTENANCEMANAGER;

    public static void setMaintDateTime(Building building, LocalDateTime maintDate) {

        building.maintDateTime = maintDate;
        DbManager.BuildingQueries.updateMaintDate(building);

    }

    public static void dailyMaintenance() {

        Logger.info("Maintenance has started");

        // Run maintenance on player buildings

        if (ConfigManager.MB_WORLD_MAINTENANCE.getValue().equalsIgnoreCase("true"))
            processMaintenance();
        else
            Logger.info("Maintenance Costings: DISABLED");

        Logger.info("Maintenance has completed!");
    }

    public static void processMaintenance() {

        //create list of all cities
        ConcurrentHashMap<Integer, AbstractGameObject> worldCities = DbManager.getMap(Enum.GameObjectType.City);

        //loop all cities
        for (AbstractGameObject ago : worldCities.values()) {
            if (ago.getObjectType().equals(Enum.GameObjectType.City)) {
                City city = (City) ago;
                if(city == null || city.getIsNpcOwned() == 1)
                    continue;

                Building tol = city.getTOL();
                if(tol == null)
                    continue;

                if(tol.maintDateTime.toLocalDate().equals(LocalDateTime.now().toLocalDate()) || LocalDateTime.now().toLocalDate().isAfter(tol.maintDateTime.toLocalDate())){
                    // today is maintenance day
                    processTolMaintenance(tol, city.getWarehouse());
                }
            }
        }
    }

    public static void processTolMaintenance(Building tol, Warehouse warehouse){
        //create the required resource maintenance list
        HashMap<Integer,Integer> maintCosts = new HashMap<>();
        maintCosts.put(7,3000000);
        if(tol.getRank() == 8){
            maintCosts.put(1580000,3000);//stone
            maintCosts.put(1580004,3000);//lumber
            maintCosts.put(1580017,5);//galvor
            maintCosts.put(1580018,5);//wormwood
        }else {
            //not r8, only need to process gold value and we're done
            int maintenanceDue = maintCosts.get(7);
            int strongboxGold = tol.getStrongboxValue();
            if (strongboxGold > 0) {
                if (strongboxGold > maintenanceDue) {
                    //enough gold in strongbox to cover all of maintenance
                    maintenanceDue = 0;
                    strongboxGold -= maintenanceDue;
                    tol.setStrongboxValue(strongboxGold); //update strongbox value
                    setMaintDateTime(tol, tol.maintDateTime.plusDays(7)); //maintenance paid, set next maintenance date for 1 week from today
                    return; //maintenance is paid, all done
                } else {
                    maintenanceDue -= strongboxGold;
                    strongboxGold = 0;
                }
            }
            //now we need to take the remaining maintenance from the warehouse
            int warehouseGold = 0;
            if (warehouse != null) {
                warehouseGold = warehouse.getResources().get(ItemBase.getItemBase(7));
            }
            if (warehouseGold >= maintenanceDue) {
                //we have enough gold to process maintenance
                tol.setStrongboxValue(strongboxGold); //update the strongbox now that we are sure maintenance is being paid
                warehouseGold -= maintenanceDue;
                warehouse.getResources().put(ItemBase.getItemBase(7),warehouseGold);
                DbManager.WarehouseQueries.updateGold(warehouse, warehouseGold);
                setMaintDateTime(tol, tol.maintDateTime.plusDays(7)); //maintenance paid, set next maintenance date for 1 week from today
                //maintenance is paid, all done
            } else {
                //failed maintenance, derank asset
                HandleMaintenanceDerank(tol); //handle derank or potential destruction of the city
            }
            return;
        }

        //handle r8 ToL maintenance here after the fact
        boolean success = true;

        int strongboxGold = tol.getStrongboxValue();
        int maintenanceGoldRequired = maintCosts.get(7);

        //remove any gold from strongbox to start paying maintenance
        if(tol.getStrongboxValue() > 0){
            if(tol.getStrongboxValue() > maintenanceGoldRequired){
                strongboxGold -= maintenanceGoldRequired;
                maintCosts.put(7,0);
            }else{
                maintCosts.put(7,maintCosts.get(7) - strongboxGold);
                strongboxGold = 0;
            }
        }
        for(Integer ibId : maintCosts.keySet()){
            if (warehouse != null) {
                if(warehouse.getResources().get(ItemBase.getItemBase(ibId)) == null)
                    success = false; //this resource is not in the warehouse, failed to pay maintenance

                int resourceCount = warehouse.getResources().get(ItemBase.getItemBase(ibId));
                if(resourceCount < maintCosts.get(ibId))
                    success = false; //not enough of this type to pay maintenance, maintenance failed to pay
            }else{
                success = false; //warehouse is null, cannot pay resource maintenance
            }
        }
        if(success == true){
            //determined there is enough of each resourceType to withdraw maintenance
            tol.setStrongboxValue(strongboxGold);
            int goldLeft = warehouse.getResources().get(ItemBase.getItemBase(7)) - maintCosts.get(7);
            int galvorLeft = warehouse.getResources().get(ItemBase.getItemBase(1580017)) - maintCosts.get(1580017);
            int lumberLeft = warehouse.getResources().get(ItemBase.getItemBase(1580004)) - maintCosts.get(1580004);
            int stoneLeft = warehouse.getResources().get(ItemBase.getItemBase(1580000)) - maintCosts.get(1580000);
            int wormwoodLeft = warehouse.getResources().get(ItemBase.getItemBase(1580018)) - maintCosts.get(1580018);
            DbManager.WarehouseQueries.updateGold(warehouse, goldLeft);
            DbManager.WarehouseQueries.updateStone(warehouse, stoneLeft);
            DbManager.WarehouseQueries.updateLumber(warehouse, lumberLeft);
            DbManager.WarehouseQueries.updateGalvor(warehouse, galvorLeft);
            DbManager.WarehouseQueries.updateWormwood(warehouse, wormwoodLeft);
            warehouse.getResources().put(ItemBase.getItemBase(7), goldLeft);
            warehouse.getResources().put(ItemBase.getItemBase(1580017), galvorLeft);
            warehouse.getResources().put(ItemBase.getItemBase(1580004), lumberLeft);
            warehouse.getResources().put(ItemBase.getItemBase(1580000), stoneLeft);
            warehouse.getResources().put(ItemBase.getItemBase(1580018), wormwoodLeft);
            setMaintDateTime(tol, tol.maintDateTime.plusDays(7)); //maintenance paid, set next maintenance date for 1 week from today
        }else{
            HandleMaintenanceDerank(tol);//handle derank or potential destruction of the city
        }

    }

    public static void HandleMaintenanceDerank(Building tol){
        setMaintDateTime(tol, tol.maintDateTime.plusDays(1)); //failed to pay maintenance, set next date for tomorrow
        if(tol.getRank() == 1)
            destroyAllCityAssets(tol.getCity());
        try {
           tol.destroyOrDerank(null);
        }catch(Exception e){

        }
    }
    public static void destroyAllCityAssets(City city){
        if(city == null)
            Logger.error("Maintenance Failed To Find City To Destroy");
        for(Building building : city.getParent().zoneBuildingSet){
            building.setRank(-1);
        }
        city.getParent().zoneBuildingSet.clear();
    }
}
