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


package engine.devcmd.cmds;

import engine.Enum;
import engine.Enum.BuildingGroup;
import engine.Enum.GameObjectType;
import engine.Enum.TargetColor;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.BuildingManager;
import engine.gameManager.PowersManager;
import engine.gameManager.SessionManager;
import engine.math.Vector3fImmutable;
import engine.objects.*;
import engine.powers.EffectsBase;
import engine.powers.PowersBase;
import engine.server.MBServerStatics;
import engine.util.StringUtils;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author
 */
public class InfoCmd extends AbstractDevCmd {

    public InfoCmd() {
        super("info");
    }

    @Override
    protected void _doCmd(PlayerCharacter pc, String[] words,
                          AbstractGameObject target) {
        // Arg Count Check
        if (words.length != 1) {
            this.sendUsage(pc);
            return;
        }
        if (pc == null) {
            return;
        }

        String newline = "\r\n ";

        try {
            int targetID = Integer.parseInt(words[0]);
            Building b = BuildingManager.getBuilding(targetID);
            if (b == null)
                throwbackError(pc, "Building with ID " + targetID
                        + " not found");
            else
                target = b;
        } catch (Exception e) {
        }

        if (target == null) {
            throwbackError(pc, "Target is unknown or of an invalid type."
                    + newline + "Type ID: 0x"
                    + pc.getLastTargetType().toString()
                    + "   Table ID: " + pc.getLastTargetID());
            return;
        }


        GameObjectType objType = target.getObjectType();
        int objectUUID = target.getObjectUUID();
        String output;

        output = "Target Information:" + newline;
        output += StringUtils.addWS("UUID: " + objectUUID, 20);
        output += newline;
        output += "Type: " + target.getClass().getSimpleName();
        output += " [0x" + objType.toString() + ']';

        if (target instanceof AbstractWorldObject) {
            AbstractWorldObject targetAWO = (AbstractWorldObject) target;
            Vector3fImmutable targetLoc = targetAWO.getLoc();
            output += newline;
            output += StringUtils.addWS("Lat: " + targetLoc.x, 20);
            output += "Lon: " + -targetLoc.z;
            output += newline;
            output += StringUtils.addWS("Alt: " + targetLoc.y, 20);
            output += newline;
            output += "Rot: " + targetAWO.getRot().y;
            output += newline;
            double radian = 0;


            if (targetAWO.getBounds() != null && targetAWO.getBounds().getQuaternion() != null)
                radian = targetAWO.getBounds().getQuaternion().angleY;
            int degrees = (int) Math.toDegrees(radian);


            output += "Degrees: " + degrees;
            output += newline;
        }

        switch (objType) {
            case Building:
                Building targetBuilding = (Building) target;
                output += StringUtils.addWS("Lac: "
                        + targetBuilding.getw(), 20);
                output += "Blueprint : ";
                output += targetBuilding.getBlueprintUUID();
                output += newline;

                output += " MeshUUID : ";
                output += targetBuilding.getMeshUUID();
                output += newline;

                if (targetBuilding.getBlueprintUUID() != 0)
                    output += ' ' + targetBuilding.getBlueprint().getName();

                output += newline;
                output += targetBuilding.getBlueprint() != null ? targetBuilding.getBlueprint().getBuildingGroup().name() : " no building group";

                output += newline;
                output += "EffectFlags: " + targetBuilding.getEffectFlags();
                output += newline;
                output += StringUtils.addWS("rank: " + targetBuilding.getRank(),
                        20);
                output += "HP: " + targetBuilding.getHealth() + '/'
                        + targetBuilding.getMaxHitPoints();
                output += newline;
                output += "Scale: (" + targetBuilding.getMeshScale().getX();
                output += ", " + targetBuilding.getMeshScale().getY();
                output += ", " + targetBuilding.getMeshScale().getZ() + ')';
                output += newline;
                output += "Owner UID: " + targetBuilding.getOwnerUUID();
                output += (targetBuilding.isOwnerIsNPC() ? " (NPC)" : " (PC)");
                output += newline;
                output += "ProtectionState: " + targetBuilding.getProtectionState().name();
                output += newline;

                if (targetBuilding.getUpgradeDateTime() != null) {
                    output += targetBuilding.getUpgradeDateTime().toString();
                    output += newline;
                }

                Guild guild = targetBuilding.getGuild();
                Guild nation = null;
                String guildId = "-1";
                String nationId = "-1";
                String gTag = "";
                String nTag = "";

                if (guild != null) {
                    int id = guild.getObjectUUID();

                    if (id == 0) {
                        guildId = id + " [" + guild.hashCode() + ']';
                    } else
                        guildId = Integer.toString(id);

                    gTag = guild.getGuildTag().summarySentence();
                    nation = guild.getNation();

                    if (nation != null) {
                        id = nation.getObjectUUID();
                        if (id == 0) {
                            nationId = id + " [" + nation.hashCode() + ']';
                        } else {
                            nationId = Integer.toString(id);
                        }
                        nTag = nation.getGuildTag().summarySentence();
                    }
                }
                output += StringUtils.addWS("Guild UID: " + guildId, 20);

                if (gTag.length() > 0)
                    output += "Guild crest: " + gTag;

                output += newline;
                output += StringUtils.addWS("Nation UID: " + nationId, 20);

                if (nTag.length() > 0) {
                    output += "Nation crest: " + nTag;
                }

                output += newline;


                if (targetBuilding.getBlueprint() != null) {

                    if (targetBuilding.getBlueprint().getBuildingGroup() == BuildingGroup.MINE) {
                        Mine mine = Mine.getMineFromTower(targetBuilding.getObjectUUID());

                        if (mine != null) {
                            output += newline;
                            output += "Mine active: " + mine.getIsActive();
                            output += newline;
                            output += "Was claimed: " + mine.wasClaimed;
                            output += newline;
                            output += "Mine Type: " + mine.getMineType().name;
                            output += newline;
                            output += "Expansion : " + mine.isExpansion();
                            output += newline;
                            output += "Production type: " + mine.getProduction().name();

                        }
                    }
                    output += newline;

                    if (targetBuilding.maintDateTime != null) {
                        output += targetBuilding.maintDateTime.toString();
                        output += newline;
                    }
                }

                output += "Reserve : " + targetBuilding.reserve;
                output += newline;
                output += "Strongbox : " + targetBuilding.getStrongboxValue();
                output += newline;

                // List hirelings

                if (targetBuilding.getHirelings().isEmpty() == false) {

                    output += newline;
                    output += "Hirelings List: name / slot / floor";

                    for (AbstractCharacter npc : targetBuilding.getHirelings().keySet()) {

                        if (npc.getObjectType() != GameObjectType.NPC)
                            continue;
                        output += newline + npc.getName() + " slot " + targetBuilding.getHirelings().get(npc);
                        output += newline + "location " + npc.getLoc();
                    }
                }

                ArrayList<BuildingRegions> tempList = BuildingRegions._staticRegions.get(targetBuilding.getMeshUUID());
                output += newline;
                output += "Building Regions: Size - " + tempList.size();
                output += newline;
                output += "Building Regions from Bounds: Size - " + targetBuilding.getBounds().getRegions().size();
                output += newline;

                for (Regions regions : targetBuilding.getBounds().getRegions()) {
                    //TODO ADD REGION INFO
                }

                break;
            case PlayerCharacter:
                output += newline;
                PlayerCharacter targetPC = (PlayerCharacter) target;
                output += StringUtils.addWS("Name: " + targetPC.getName(), 20);
                output += newline;
                output += "InSession : " + SessionManager.getPlayerCharacterByID(target.getObjectUUID()) != null ? " true " : " false";
                output += newline;
                output += "RaceType: " + targetPC.getRace().getRaceType().name();
                output += newline;
                output += "Race: " + targetPC.getRace().getName();
                output += newline;
                output += "Safe:" + targetPC.inSafeZone();
                output += newline;
                output += "Experience : " + targetPC.getExp();
                output += newline;
                output += "OverFlowExperience : " + targetPC.getOverFlowEXP();
                output += newline;
                output += StringUtils.addWS("Level: "
                        + targetPC.getLevel() + " (" +
                        TargetColor.getCon(targetPC, pc).toString() + ')', 20);

                Account acpc = SessionManager.getAccount(pc);
                Account ac = SessionManager.getAccount(targetPC);

                if (acpc != null && ac != null) {
                    output += "Account ID: " + ac.getObjectUUID();
                    output += newline;
                    output += "Access Level: " + ac.status.name();
                } else
                    output += "Account ID: UNKNOWN";

                output += newline;
                output += "Inventory Weight:" + (targetPC.getCharItemManager().getInventoryWeight() + targetPC.getCharItemManager().getEquipWeight());
                output += newline;
                output += "Max Inventory Weight:" + ((int) targetPC.statStrBase * 3);
                output += newline;
                output += "ALTITUDE :" + targetPC.getAltitude();
                output += newline;
                output += "BuildingID :" + targetPC.getInBuildingID();
                output += newline;
                output += "inBuilding :" + targetPC.getInBuilding();
                output += newline;
                output += "inFloor :" + targetPC.getInFloorID();
                output += newline;

                BaseClass baseClass = targetPC.getBaseClass();

                if (baseClass != null)
                    output += StringUtils.addWS("Class: " + baseClass.getName(), 20);
                else
                    output += StringUtils.addWS("", 20);

                PromotionClass promotionClass = targetPC.getPromotionClass();
                if (promotionClass != null) {
                    output += "Pro. Class: " + promotionClass.getName();
                } else {
                    output += "Pro. Class: ";
                }

                output += newline;
                output += "====Guild Info====";
                output += newline;

                if (targetPC.getGuild() != null) {
                    output += "Name: " + targetPC.getGuild().getName();
                    output += newline;
                    output += "State: " + targetPC.getGuild().getGuildState();
                    output += newline;
                    output += "Realms Owned:" + targetPC.getGuild().getRealmsOwned();
                    output += newline;
                    output += "====Nation====";
                    output += newline;
                    output += "Nation Name: " + targetPC.getGuild().getNation().getName();
                    output += newline;
                    output += "Nation State: " + targetPC.getGuild().getNation().getGuildState();
                    output += newline;
                    output += "Realms Owned:" + targetPC.getGuild().getNation().getRealmsOwned();
                    output += newline;
                    output += "Guild Rank:" + (GuildStatusController.getRank(targetPC.getGuildStatus()) + targetPC.getGuild().getRealmsOwnedFlag());
                }

                output += newline;
                output += "Movement State: " + targetPC.getMovementState().name();
                output += newline;
                output += "Movement Speed: " + targetPC.getSpeed();
                output += newline;
                output += "Altitude : " + targetPC.getLoc().y;
                output += newline;
                output += "Swimming : " + targetPC.isSwimming();
                output += newline;
                output += "isMoving : " + targetPC.isMoving();
                output += newline;
                output += "Zerg Multiplier : " + targetPC.ZergMultiplier + newline;
                output += "Hidden : " + targetPC.getHidden() + newline;
                output += "Target Loc: " + targetPC.loc + newline;
                output += "Player Loc: " + pc.loc + newline;
                output += "Distance Squared: " + pc.loc.distanceSquared(targetPC.loc);
                break;

            case NPC:
                NPC targetNPC = (NPC) target;
                output += "databaseID: " + targetNPC.getDBID() + newline;
                output += "Name: " + targetNPC.getName();
                output += newline;
                output += StringUtils.addWS("Level: " + targetNPC.getLevel(), 20);

                MobBase mobBase;

                if (targetNPC.getContract() == null)
                    mobBase = targetNPC.getMobBase();
                else
                    mobBase = MobBase.getMobBase(targetNPC.getContract().getMobbaseID());

                if (mobBase != null) {
                    output += "Mobbbase: " + mobBase.getObjectUUID();
                    output += newline;
                    output += "Flags: " + mobBase.getFlags().toString();
                }

                output += newline;
                output += "Spawn: (" + targetNPC.getBindLoc().getX();
                output += ", " + targetNPC.getBindLoc().getY();
                output += ", " + targetNPC.getBindLoc().getZ() + ')';
                output += newline;
                output += "ContractID: " + targetNPC.getContractID();
                output += newline;
                output += "InventorySet: " + targetNPC.getContract().inventorySet;
                output += newline;
                output += targetNPC.getContract().getAllowedBuildings().toString();
                output += newline;
                output += "Extra Rune: " + targetNPC.getContract().getExtraRune();

                output += newline;
                output += "isTrainer: " + targetNPC.getContract().isTrainer();
                output += newline;
                output += "Buy Cost: " + targetNPC.getBuyPercent();
                output += "\tSell Cost: " + targetNPC.getSellPercent();
                output += newline;
                output += "fromInit: " + targetNPC.isStatic();
                output += newline;
                if (mobBase != null) {
                    output += newline;
                    output += "Slottable: " + targetNPC.getContract().getAllowedBuildings().toString();
                    output += newline;
                    output += "EquipSet: " + targetNPC.getEquipmentSetID();
                    output += newline;
                    output += "Parent Zone LoadNum : " + targetNPC.getParentZone().getLoadNum();

                }

                if (targetNPC.region != null) {
                    output += newline;
                    output += "Region found: " + "Building : " + targetNPC.region.parentBuildingID + newline;
                    output += "building level : " + targetNPC.region.level + newline;
                    output += "building room : " + targetNPC.region.room + newline;
                } else {
                    output += newline;
                    output += "No region was found.";
                }

                if (targetNPC.getBuilding() != null) {
                    output += newline;
                    output += "Building : " + targetNPC.getBuilding();
                } else {
                    output += newline;
                    output += "No building found.";
                }
                break;
            case Mob:
                Mob targetMob = (Mob) target;
                output += "databaseID: " + targetMob.getDBID() + newline;
                output += "Name: " + targetMob.getName();
                output += newline;
                output += StringUtils.addWS("Level: " + targetMob.getLevel(), 20);
                mobBase = targetMob.getMobBase();
                if (mobBase != null)
                    output += "RaceID: " + mobBase.getObjectUUID();
                else
                    output += "RaceID: " + targetMob.getLoadID();
                output += newline;
                try {
                    output += "notEnemy: " + targetMob.notEnemy.toString();
                    output += newline;
                    output += "enemy: " + targetMob.enemy.toString();
                    output += newline;
                } catch (Exception ex) {
                    //who cares its info
                }
                output += "Spawn: (" + targetMob.getBindLoc().getX();
                output += ", " + targetMob.getBindLoc().getY();
                output += ", " + targetMob.getBindLoc().getZ() + ')';
                output += newline;
                if (targetMob.isPet()) {
                    output += "isPet: true";
                    output += newline;
                    if ((targetMob.agentType.equals(Enum.AIAgentType.PET)))
                        output += "isSummonedPet: true";
                    else
                        output += "isSummonedPet: false";
                    PlayerCharacter owner = targetMob.getOwner();
                    if (owner != null)
                        output += "     owner: " + owner.getObjectUUID();
                    output += newline;
                    output += "assist: " + targetMob.assist + "   resting: " + targetMob.isSit();
                    output += newline;
                }
                if (targetMob.getMobBase() != null) {
                    output += "Mobbase: " + targetMob.getMobBase().getObjectUUID();
                    output += newline;
                    output += "Flags: " + targetMob.getMobBase().getFlags().toString();
                    output += newline;

                }
                if ((targetMob.agentType.equals(Enum.AIAgentType.MOBILE))) {
                    output += "SpawnRadius: " + targetMob.getSpawnRadius();
                    output += newline;
                    output += "Spawn Timer: " + targetMob.getSpawnTimeAsString();
                    output += newline;
                }
                output += StringUtils.addWS("isAlive: "
                        + targetMob.isAlive(), 20);
                output += newline;
                //output += "Mob State: " + targetMob.state.name();

                output += newline;
                output += "Speed : " + targetMob.getSpeed();
                output += newline;
                output += "EquipSet: " + targetMob.equipmentSetID;
                output += newline;
                try {
                    output += "Parent Zone LoadNum : " + targetMob.getParentZone().getLoadNum();
                } catch (Exception ex) {
                    //who cares
                }
                output += newline;
                output += "isMoving : " + targetMob.isMoving();
                if (targetMob.region != null) {
                    output += newline;
                    output += "BuildingID : " + targetMob.region.parentBuildingID;
                    output += "building level : " + targetMob.region.level;
                    output += "building room : " + targetMob.region.room;
                }
                if (targetMob.building != null) {
                    output += "Building Name: " + targetMob.building.getName() + newline;
                    output += "BuildingID : " + targetMob.building + newline;
                    output += "Bind Loc : " + targetMob.getBindLoc() + newline;
                    output += "Curr Loc : " + targetMob.getLoc() + newline;
                } else {
                    output += newline;
                    output += "No building found." + newline;
                }

                output += "Damage: " + targetMob.mobBase.getDamageMin() + " - " + targetMob.mobBase.getDamageMax() + newline;
                output += "ATR: " + targetMob.mobBase.getAttackRating() + newline;
                output += "DEF: " + targetMob.defenseRating + newline;
                output += "RANGE: " + targetMob.getRange() + newline;
                output += "Effects:" + newline;
                for(MobBaseEffects mbe : targetMob.mobBase.mobbaseEffects){
                    EffectsBase eb = PowersManager.getEffectByToken(mbe.getToken());
                    output += eb.getName() + newline;
                }
                break;
            case Item:  //intentional passthrough
            case MobLoot:
                Item item = (Item) target;
                ItemBase itemBase = item.getItemBase();
                output += StringUtils.addWS("ItemBase: " + itemBase.getUUID(), 20);
                output += "Weight: " + itemBase.getWeight();
                output += newline;
                DecimalFormat df = new DecimalFormat("###,###,###,###,##0");
                output += StringUtils.addWS("Qty: "
                        + df.format(item.getNumOfItems()), 20);
                output += "Charges: " + item.getChargesRemaining()
                        + '/' + item.getChargesMax();
                output += newline;
                output += "Name: " + itemBase.getName();
                output += newline;
                output += item.getContainerInfo();

                throwbackInfo(pc, output);

                output = "Effects:" + newline;
                ConcurrentHashMap<String, Effect> effects = item.getEffects();
                for (String name : effects.keySet()) {
                    Effect eff = effects.get(name);
                    output += eff.getEffectsBase().getIDString();
                    output += newline;
                    //	output += eff.getEffectToken() + (eff.bakedInStat() ? " (baked in)" : "") + newline;
                }

                break;

            case Corpse:
                Corpse corpse = (Corpse)target;
                Long timeLeft = MBServerStatics.CORPSE_CLEANUP_TIMER_MS - (System.currentTimeMillis() - corpse.spawnedTime);
                output += "Despawn in: " + timeLeft;
                output += newline;
                break;
        }

        throwbackInfo(pc, output);
    }

    @Override
    protected String _getHelpString() {
        return "Gets information on an Object.";
    }

    @Override
    protected String _getUsageString() {
        return "' /info targetID'";
    }

}