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

package engine.net.client.handlers;

import engine.Enum;
import engine.Enum.DispatchChannel;
import engine.exception.MsgSendException;
import engine.gameManager.ChatManager;
import engine.gameManager.GroupManager;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.*;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;

import static engine.math.FastMath.sqr;

public class LootMsgHandler extends AbstractClientMsgHandler {

    public LootMsgHandler() {
        super(LootMsg.class);
    }

    @Override
    protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {

        PlayerCharacter player = origin.getPlayerCharacter();

        // Member variable declaration

        LootMsg msg;

        // Member variable assignment

        msg = (LootMsg) baseMsg;

        if (player == null)
            return true;

        if (!player.isAlive())
            return true;

        Item item = msg.getItem();

        if (item == null)
            return true;

        if (item.lootLock.tryLock()) {
            try {
                Item itemRet = null;
                // get current owner
                int targetType = msg.getTargetType();
                int targetID = msg.getTargetID();

                if (targetType == Enum.GameObjectType.PlayerCharacter.ordinal() || targetType == Enum.GameObjectType.Mob.ordinal() || targetType == Enum.GameObjectType.Corpse.ordinal()) {
                } else { //needed for getting contracts for some reason
                    targetType = msg.getSourceID2();
                    targetID = msg.getUnknown01();
                }

                //can't loot while flying
                if (player.getAltitude() > 0)
                    return true;

                AbstractCharacter tar = null;
                Corpse corpse = null;

                if (targetType == Enum.GameObjectType.PlayerCharacter.ordinal() || targetType == Enum.GameObjectType.Mob.ordinal()) {

                    if (targetType == Enum.GameObjectType.PlayerCharacter.ordinal()) {
                        tar = PlayerCharacter.getFromCache(targetID);

                        if (tar == null)
                            return true;

                        if (player.getObjectUUID() != tar.getObjectUUID() && ((PlayerCharacter) tar).isInSafeZone())
                            return true;

                    } else if (targetType == Enum.GameObjectType.NPC.ordinal())
                        tar = NPC.getFromCache(targetID);
                    else if (targetType == Enum.GameObjectType.Mob.ordinal())
                        tar = Mob.getFromCache(targetID);

                    if (tar == null)
                        return true;

                    if (tar.equals(player)) {
                        ErrorPopupMsg.sendErrorMsg(player, "Cannot loot this item.");
                        return true;
                    }

                    if (player.getLoc().distanceSquared2D(tar.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) {
                        ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse.");
                        Logger.info(player.getFirstName() + " tried looting at " + player.getLoc().distance2D(tar.getLoc()) + " distance.");
                        return true;
                    }

                    //can't loot from someone who is alive.
                    if (AbstractWorldObject.IsAbstractCharacter(tar)) {
                        if (tar.isAlive())
                            return true;
                        //					Logger.error("WorldServer.loot", "Looting from live player");
                    }

                    if (!GroupManager.goldSplit(player, item, origin, tar)) {

                        if (tar.charItemManager != null) {

                            itemRet = tar.charItemManager.lootItemFromMe(item, player, origin);

                            //Take equipment off mob
                            if (tar.getObjectType() == Enum.GameObjectType.Mob && itemRet != null) {
                                Mob mobTarget = (Mob) tar;

                                if (item != null && item.getObjectType() == Enum.GameObjectType.MobLoot) {

                                    for (Item equip : mobTarget.charItemManager.equipped.values()) {

                                        TransferItemFromEquipToInventoryMsg back = new TransferItemFromEquipToInventoryMsg(mobTarget, equip.equipSlot);
                                        DispatchMessage.dispatchMsgToInterestArea(mobTarget, back, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);

                                        LootMsg lootMsg = new LootMsg(0, 0, tar.getObjectType().ordinal(), tar.getObjectUUID(), equip);
                                        Dispatch dispatch = Dispatch.borrow(player, lootMsg);
                                        DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
                                        break;
                                    }
                                }
                            }
                        }

                    }
                } else if (targetType == Enum.GameObjectType.Corpse.ordinal()) {
                    corpse = Corpse.getCorpse(targetID);

                    if (corpse == null)
                        return true;

                    if (player.getLoc().distanceSquared2D(corpse.getLoc()) > sqr(MBServerStatics.LOOT_RANGE)) {
                        ErrorPopupMsg.sendErrorMsg(player, "You are too far away to loot this corpse.");
                        Logger.info(player.getFirstName() + " tried looting at " + player.getLoc().distance2D(corpse.getLoc()) + " distance.");
                        return true;
                    }

                    //can't loot other players in safe zone.
                    if (corpse.getBelongsToType() == Enum.GameObjectType.PlayerCharacter.ordinal()) {

                        if (player.getObjectUUID() == corpse.getBelongsToID())
                            itemRet = corpse.lootItem(item, player);
                        else if (!GroupManager.goldSplit(player, item, origin, corpse)) {
                            itemRet = corpse.lootItem(item, player);

                        }

                        if (itemRet == null)
                            return true;

                        if (item.template.item_type.equals(engine.Enum.ItemType.GOLD)) {
                            // this is done to prevent the temporary goldItem item
                            // (from the mob) from appearing in player's inventory.
                            // It also updates the goldItem quantity display
                            UpdateGoldMsg updateTargetGold = null;

                            if (corpse != null)
                                updateTargetGold = new UpdateGoldMsg(corpse);

                            updateTargetGold.configure();
                            DispatchMessage.dispatchMsgToInterestArea(corpse, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);

                            UpdateGoldMsg ugm = new UpdateGoldMsg(player);
                            ugm.configure();
                            Dispatch dispatch = Dispatch.borrow(player, ugm);
                            DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);

                            // respond back loot message. Try sending to everyone.

                        } else
                            DispatchMessage.dispatchMsgToInterestArea(corpse, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true);


                        //TODO send group loot message if player is grouped and visible
                        Group group = GroupManager.getGroup(player);

                        if (group != null && group.getSplitGold() && (item.template.item_type.equals(engine.Enum.ItemType.GOLD) == false)) {
                            String name = item.getName();
                            String text = player.getFirstName() + " has looted " + name + '.';
                            ChatManager.chatGroupInfoCanSee(player, text);
                        }

                        return true;
                    }

                } else
                    return true;

                if (itemRet == null)
                    return true;

                if (item.template.item_type.equals(engine.Enum.ItemType.GOLD)) {
                    // this is done to prevent the temporary goldItem item
                    // (from the mob) from appearing in player's inventory.
                    // It also updates the goldItem quantity display
                    UpdateGoldMsg updateTargetGold = null;

                    if (tar != null)
                        updateTargetGold = new UpdateGoldMsg(tar);
                    else if (corpse != null)
                        updateTargetGold = new UpdateGoldMsg(corpse);

                    updateTargetGold.configure();
                    DispatchMessage.dispatchMsgToInterestArea(tar, updateTargetGold, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);

                    UpdateGoldMsg ugm = new UpdateGoldMsg(player);
                    ugm.configure();
                    Dispatch dispatch = Dispatch.borrow(player, ugm);
                    DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);

                    // respond back loot message. Try sending to everyone.

                } else {
                    msg.setSourceType1(0);
                    msg.setSourceType2(0);
                    msg.setSourceID1(0);
                    msg.setSourceID2(0);
                    Dispatch dispatch = Dispatch.borrow(player, msg);
                    //DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);
                    DispatchMessage.dispatchMsgToInterestArea(tar, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, true);
                    LootMsg newItemMsg = new LootMsg(Enum.GameObjectType.PlayerCharacter.ordinal(), player.getObjectUUID(), 0, 0, itemRet);
                    dispatch = Dispatch.borrow(player, newItemMsg);
                    DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY);

                    //player.getCharItemManager().updateInventory();
                }

                //TODO send group loot message if player is grouped and visible
                Group group = GroupManager.getGroup(player);

                if (group != null && group.getSplitGold() && (item.template.item_type.equals(engine.Enum.ItemType.GOLD) == false)) {
                    String name = item.getName();
                    String text = player.getFirstName() + " has looted " + name + '.';
                    ChatManager.chatGroupInfoCanSee(player, text);
                }
            } catch (Exception e) {
                Logger.info(e.getMessage());
            } finally {
                item.lootLock.unlock();
            }
        }

        return true;
    }

}