using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WingsAPI.Game.Extensions.Groups;
using WingsAPI.Game.Extensions.ItemExtension.Inventory;
using WingsEmu.Game._enum;
using WingsEmu.Game._Guri;
using WingsEmu.Game._Guri.Event;
using WingsEmu.Game._i18n;
using WingsEmu.Game._ItemUsage.Configuration;
using WingsEmu.Game.Chat;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Extensions.Mates;
using WingsEmu.Game.Helpers.Damages;
using WingsEmu.Game.Inventory;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Managers.StaticData;
using WingsEmu.Game.Mates;
using WingsEmu.Game.Networking;
using WingsEmu.Packets.ClientPackets;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Chat;
using ChatType = WingsEmu.Game._playerActionLogs.ChatType;

namespace WingsEmu.Plugins.BasicImplementations.Guri;

public class InteractionGuriHandler : IGuriHandler
{
    private readonly IForbiddenNamesManager _forbiddenNamesManager;
    private readonly IItemsManager _itemsManager;

    private readonly IGameLanguageService _languageService;
    private readonly ISpPartnerConfiguration _spPartner;

    public InteractionGuriHandler(IGameLanguageService languageService, IItemsManager itemsManager, ISpPartnerConfiguration spPartner, IForbiddenNamesManager forbiddenNamesManager)
    {
        _languageService = languageService;
        _itemsManager = itemsManager;
        _spPartner = spPartner;
        _forbiddenNamesManager = forbiddenNamesManager;
    }

    public long GuriEffectId => 4;

    public async Task ExecuteAsync(IClientSession session, GuriEvent guriPacket)
    {
        if (!long.TryParse(guriPacket.Packet[3], out long guriType))
        {
            return;
        }

        if (!long.TryParse(guriPacket.Packet[5], out long itemSpeaker))
        {
            return;
        }

        if (itemSpeaker == 999)
        {
            guriType = 999;
        }

        string message;
        string[] valueSplit;

        switch (guriType)
        {
            case 1:
                if (session.CantPerformActionOnAct4())
                {
                    return;
                }

                if (session.PlayerEntity.RainbowBattleComponent.IsInRainbowBattle)
                {
                    return;
                }

                if (string.IsNullOrWhiteSpace(guriPacket.Value))
                {
                    return;
                }

                if (!guriPacket.User.HasValue)
                {
                    return;
                }

                IMateEntity mateEntity = session.PlayerEntity.MateComponent.GetMate(s => s.Id == guriPacket.User && s.MateType == MateType.Pet);
                if (guriPacket.Value.Length > 15)
                {
                    session.SendInfo(_languageService.GetLanguage(GameDialogKey.ITEM_INFO_PET_NAME_TOO_LONG, session.UserLanguage));
                    return;
                }

                if (mateEntity == null)
                {
                    return;
                }

                var rg = new Regex(@"^[a-zA-Z0-9_\-\*]*$");
                if (rg.Matches(guriPacket.Value).Count != 1)
                {
                    return;
                }

                string expectedName = guriPacket.Value;
                mateEntity.MateName = expectedName;

                if (mateEntity.Position == default)
                {
                    mateEntity.ChangePosition(session.PlayerEntity.Position);
                }

                mateEntity.MapInstance.Broadcast(s => mateEntity.GenerateIn(_languageService, s.UserLanguage, _spPartner));

                session.RefreshParty(_spPartner);
                session.SendScnPackets();
                session.SendScpPackets();
                await session.RemoveItemFromInventory((short)ItemVnums.NAME_TAG);

                break;
            // Presentation message
            case 2:
                if (guriPacket.Value == null)
                {
                    return;
                }

                bool isLimitedItem = session.PlayerEntity.HasItem((short)ItemVnums.SELF_INTRODUCTION_LIMITED);
                if (!session.PlayerEntity.HasItem((short)ItemVnums.SELF_INTRODUCTION) && !isLimitedItem)
                {
                    return;
                }

                short itemVnumToRemove = isLimitedItem ? (short)ItemVnums.SELF_INTRODUCTION_LIMITED : (short)ItemVnums.SELF_INTRODUCTION;

                message = string.Empty;
                valueSplit = guriPacket.Value.Split(' ');
                message = valueSplit.Aggregate(message, (current, t) => current + t + "^");
                message = message[..^1]; // Remove the last ^
                message = message.Trim();
                if (message.Length > 60)
                {
                    message = message.Substring(0, 60);
                }

                session.PlayerEntity.Biography = message;
                session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.INTERACTION_CHATMESSAGE_INTRODUCTION_SET, session.UserLanguage), ChatMessageColorType.Yellow);
                await session.RemoveItemFromInventory(itemVnumToRemove);

                break;

            case 3:
                bool haveLimitedSpeaker = session.PlayerEntity.HasItem((short)ItemVnums.SPEAKER_LIMITED);
                bool haveSpeaker = session.PlayerEntity.HasItem((short)ItemVnums.SPEAKER);
                if (!haveLimitedSpeaker && !haveSpeaker)
                {
                    return;
                }

                if (session.PlayerEntity.RainbowBattleComponent.IsInRainbowBattle)
                {
                    session.SendChatMessage(session.GetLanguage(GameDialogKey.ITEM_MESSAGE_CANT_USE), ChatMessageColorType.Yellow);
                    return;
                }

                if (guriPacket.Value == null)
                {
                    return;
                }

                valueSplit = guriPacket.Value.Split(' ');
                message = valueSplit.Aggregate("", (current, t) => current + t + " ");

                if (session.IsMuted())
                {
                    session.SendMuteMessage();
                    return;
                }

                await session.EmitEventAsync(new ChatSpeakerEvent(SpeakerType.Normal_Speaker, message));

                if (haveLimitedSpeaker)
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.SPEAKER_LIMITED);
                }
                else
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.SPEAKER);
                }

                break;

            case 4:
                if (session.CantPerformActionOnAct4())
                {
                    return;
                }

                bool haveLimitedBubble = session.PlayerEntity.HasItem((short)ItemVnums.BUBBLE_LIMITED);
                bool haveBubble = session.PlayerEntity.HasItem((short)ItemVnums.BUBBLE);
                if (!haveLimitedBubble && !haveBubble)
                {
                    return;
                }

                if (session.PlayerEntity.RainbowBattleComponent.IsInRainbowBattle)
                {
                    session.SendChatMessage(session.GetLanguage(GameDialogKey.ITEM_MESSAGE_CANT_USE), ChatMessageColorType.Yellow);
                    return;
                }

                if (session.IsMuted())
                {
                    session.SendMuteMessage();
                    return;
                }

                session.PlayerEntity.Bubble = DateTime.UtcNow;
                string bubbleMessage = guriPacket.Value;
                if (bubbleMessage.Length > 60)
                {
                    bubbleMessage = bubbleMessage.Substring(0, 60);
                }

                session.PlayerEntity.SaveBubble(bubbleMessage);
                session.SendPacket(new CsprPacket { Message = bubbleMessage });

                if (haveLimitedBubble)
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.BUBBLE_LIMITED);
                }
                else
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.BUBBLE);
                }

                await session.EmitEventAsync(new ChatGenericEvent
                {
                    Message = bubbleMessage,
                    ChatType = ChatType.SpeechBubble
                });
                break;

            case 999:
                haveLimitedSpeaker = session.PlayerEntity.HasItem((short)ItemVnums.SPEAKER_LIMITED);
                haveSpeaker = session.PlayerEntity.HasItem((short)ItemVnums.SPEAKER);
                if (!haveLimitedSpeaker && !haveSpeaker)
                {
                    return;
                }

                if (!Enum.TryParse(guriPacket.Packet[6], out InventoryType type))
                {
                    return;
                }

                if (!short.TryParse(guriPacket.Packet[7], out short slot))
                {
                    return;
                }

                if (session.PlayerEntity.RainbowBattleComponent.IsInRainbowBattle)
                {
                    session.SendChatMessage(session.GetLanguage(GameDialogKey.ITEM_MESSAGE_CANT_USE), ChatMessageColorType.Yellow);
                    return;
                }

                if (session.IsMuted())
                {
                    session.SendMuteMessage();
                    return;
                }

                InventoryItem item = session.PlayerEntity.GetItemBySlotAndType(slot, type);

                if (item == null)
                {
                    return;
                }

                string messageItem = $"{guriPacket.Value.Remove(0, 4).Replace(" ", "|")}";

                // check, if itemName is the same as in {}
                string itemName = _languageService.GetLanguage(GameDataType.Item, _itemsManager.GetItem(item.ItemInstance.ItemVNum).Name, session.UserLanguage).Replace(" ", "|");
                int firstItem = messageItem.IndexOf("{", StringComparison.Ordinal) + "{".Length;
                int lastItem = messageItem.LastIndexOf("}", StringComparison.Ordinal);
                string result = messageItem.Substring(firstItem, lastItem - firstItem);
                messageItem = messageItem.Replace(result, "%s");
                messageItem = messageItem.Trim();

                await session.EmitEventAsync(new ChatSpeakerEvent(SpeakerType.Items_Speaker, messageItem, item.ItemInstance));
                if (haveLimitedSpeaker)
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.SPEAKER_LIMITED);
                }
                else
                {
                    await session.RemoveItemFromInventory((short)ItemVnums.SPEAKER);
                }

                break;
        }
    }
}