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


package engine.net.client.msg;

import engine.Enum;
import engine.gameManager.SessionManager;
import engine.net.*;
import engine.net.client.ClientConnection;
import engine.net.client.Protocol;
import engine.objects.Guild;
import engine.objects.GuildStatusController;
import engine.objects.PlayerCharacter;
import engine.objects.PromotionClass;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;

import java.util.ArrayList;

public class WhoResponseMsg extends ClientNetMsg {

    private static int worldPop;
    private int unknown01;
    private ArrayList<PlayerCharacter> members = new ArrayList<>();

    /**
     * This is the general purpose constructor.
     */
    public WhoResponseMsg() {
        super(Protocol.WHORESPONSE);
        this.unknown01 = 1;
    }

    /**
     * This constructor is used by NetMsgFactory. It attempts to deserialize the
     * ByteBuffer into a message. If a BufferUnderflow occurs (based on reading
     * past the limit) then this constructor Throws that Exception to the
     * caller.
     */
    public WhoResponseMsg(AbstractConnection origin, ByteBufferReader reader) {
        super(Protocol.WHORESPONSE, origin, reader);
    }

    /**
     * @return the worldPop
     */
    public static int getWorldPop() {
        return WhoResponseMsg.worldPop;
    }

    /**
     * @param worldPop the worldPop to set
     */
    public static void setWorldPop(int worldPop) {
        WhoResponseMsg.worldPop = worldPop;
    }

    public static void HandleResponse(int set, int filterType, String filter, ClientConnection origin) {

        WhoResponseMsg msg = new WhoResponseMsg();
        WhoResponseMsg.setWorldPop(SessionManager.getAllActivePlayerCharacters().size());

        PlayerCharacter playerCharacter = SessionManager.getPlayerCharacter(origin);

        if (playerCharacter != null) {
            //check threshold
            long currentTime = System.currentTimeMillis();
            long timestamp = playerCharacter.getTimeStamp("whoWindow");
            long dif = currentTime - timestamp;
            if (dif < MBServerStatics.WHO_WINDOW_THRESHOLD)
                return;
            playerCharacter.setTimeStamp("whoWindow", currentTime);
        }

        if (playerCharacter == null) {
        } else if (filterType == 0) { // No Filter, send everyone
            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (player.isActive())
                        if (!isAdmin(player))
                            if (!HandleSet(set, player, playerCharacter, msg))
                                break;
        } else if (filterType == 1) { // Race Filter
            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (!isAdmin(player))
                        if (player.isActive()) {
                            String[] race = player.getRace().getName().split(",");
                            if (filter.compareTo(race[0]) == 0)
                                if (!HandleSet(set, player, playerCharacter, msg))
                                    break;
                        }
        } else if (filterType == 2) { // Class Filter
            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (!isAdmin(player))
                        if (player.isActive()) {
                            if (filter.compareTo(player.getBaseClass().getName()) == 0 || (player.getPromotionClass() != null && filter.compareTo(player.getPromotionClass().getName()) == 0))
                                if (!HandleSet(set, player, playerCharacter, msg))
                                    break;


                            // TODO Promotion Class needs added to
                            // PlayerCharacter
                            // else if
                            // (filter.compareTo(pc.getPromotionClass().getName())
                            // == 0)
                            // if (!HandleSet(set, pc, ori, msg))
                            // break;
                        }
        } else if (filterType == 3) { // Level Filter
            String range[] = filter.split(" ");
            int low;
            int high;

            try {
                low = Integer.parseInt(range[0]);
            } catch (NumberFormatException e) {
                low = 1;
                Logger.error("WhoResponseMsg: Low value in filter is not a proper integer. Defaulting to 1. Error = "
                        + e.getMessage());
            }

            try {
                high = Integer.parseInt(range[1]);
            } catch (NumberFormatException e) {
                high = 1;
                Logger.error(
                        "WhoResponseMsg: High value in filter is not a proper integer. Defaulting to 75. Error = " + e.getMessage());
            }

            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (!isAdmin(player))
                        if (player.isActive())
                            if (player.getLevel() >= low && player.getLevel() <= high)
                                if (!HandleSet(set, player, playerCharacter, msg))
                                    break;
        } else if (filterType == 4) { // Name Filter
            filter = filter.toLowerCase();
            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (!isAdmin(player))
                        if (player.isActive())
                            if (player.getName().toLowerCase().indexOf(filter) > -1)
                                if (!HandleSet(set, player, playerCharacter, msg))
                                    break;
        } else if (filterType == 6) { // Status Filter
            int type = Integer.parseInt(filter);
            for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters())
                if (player != null)
                    if (!isAdmin(player))
                        if (player.isActive()) {
                            if (type == 1) {
                                if (player.isLFGroup())
                                    if (!HandleSet(set, player, playerCharacter, msg))
                                        break;
                            } else if (type == 2) {
                                if (player.isLFGuild())
                                    if (!HandleSet(set, player, playerCharacter, msg))
                                        break;
                            } else if (type == 3) {
                                if (player.isRecruiting())
                                    if (!HandleSet(set, player, playerCharacter, msg))
                                        break;
                            } else
                                break;
                        }
        }

        Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), msg);
        DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);

    }

    private static boolean HandleSet(int set, PlayerCharacter a, PlayerCharacter b, WhoResponseMsg msg) {
        // This function handles the sets. 0 = search all, 1 = search nation,
        // 2 = search guild. Returns true until 100 (max) players found

        if (set == 0) { // All
            return msg.addMember(a);
        } else if (set == 1) { // Nation
            if (compareNation(a, b))
                return msg.addMember(a);
        } else if (set == 2) { // Guild
            if (compareGuild(a, b))
                return msg.addMember(a);
        }
        return true;
    }

    private static boolean isAdmin(PlayerCharacter pc) {
        PromotionClass promo = pc.getPromotionClass();
        if (promo == null)
            return false;
        return promo.getObjectUUID() <= 2503 || promo.getObjectUUID() >= 2527;
    }

    private static boolean compareGuild(PlayerCharacter a, PlayerCharacter b) {
        if (a == null || b == null)
            return false;
        return Guild.sameGuild(a.getGuild(), b.getGuild());
    }

    private static boolean compareNation(PlayerCharacter a, PlayerCharacter b) {
        if (a == null || b == null)
            return false;
        Guild aG = a.getGuild();
        Guild bG = b.getGuild();
        if (aG == null || bG == null)
            return false;
        return (aG.getNation() == bG.getNation()) && aG.getNation() != null;
    }

    /**
     * Serializes the subclass specific items to the supplied NetMsgWriter.
     */
    @Override
    protected void _serialize(ByteBufferWriter writer) {
        writer.putInt(unknown01);
        writer.putInt(worldPop);
        int size = this.members.size();
        writer.putInt(size);
        //PlayerCharacter pc : this.members
        for (PlayerCharacter pc : this.members) {
            writer.putInt(pc.getObjectType().ordinal());
            writer.putInt(pc.getObjectUUID());
            writer.putString(pc.getFirstName());
            writer.putString(pc.getLastName());
            writer.putInt(pc.getRaceToken());
            writer.putInt(pc.getClassToken());
            writer.putInt(pc.getLevel());
            writer.putInt(0); // unknown 0
            writer.putInt(pc.isMale() ? 1 : 2); //gender?
            writer.putInt(0); // unknown 0
            Guild guild = pc.getGuild();
            if (guild != null) {
                writer.put((byte) 1); // Send Guild Info
                writer.put((byte) 1); // SkipPartTwo
                writer.putString(guild.getName());
                writer.putInt(guild.getCharter()); // Charter Type
                writer.putInt(GuildStatusController.getTitle(pc.getGuildStatus()));
                writer.putString("what"); // City?, Skip if SkipPartTwo = 0x00
            } else {
                writer.put((byte) 0); // Don't Send guild info
                writer.put((byte) 0); // Don't send last string
            }
        }
    }

    /**
     * Deserializes the subclass specific items from the supplied NetMsgReader.
     */
    @Override
    protected void _deserialize(ByteBufferReader reader) {
        this.unknown01 = reader.getInt();
        WhoResponseMsg.worldPop = reader.getInt();
        // TODO implement Deserialization
    }

    /**
     * @return the number of PlayerCharacters
     */
    public int getSize() {
        return this.members.size();
    }

    /**
     * @return the unknown01
     */
    public int getUnknown01() {
        return unknown01;
    }

    /**
     * @param unknown01 the unknown01 to set
     */
    public void setUnknown01(int unknown01) {
        this.unknown01 = unknown01;
    }

    public boolean addMember(PlayerCharacter pc) {
        if (this.members.size() > 100)
            return false;
        this.members.add(pc);
        return true;
    }

    @Override
    protected int getPowerOfTwoBufferSize() {
        return 14;
    }

}
