using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using PhoenixLib.Events;
using WingsEmu.DTOs.Maps;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Characters;
using WingsEmu.Game.Characters.Events;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Groups;
using WingsEmu.Game.Groups.Events;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Networking;
using WingsEmu.Game.Relations;
using WingsEmu.Game.RespawnReturn.Event;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Chat;

namespace WingsEmu.Plugins.BasicImplementations.Event.Groups;

public class GroupActionEventHandler : IAsyncEventProcessor<GroupActionEvent>
{
    private readonly IGroupFactory _groupFactory;
    private readonly IInvitationManager _invitation;
    private readonly IGameLanguageService _language;
    private readonly ISessionManager _sessionManager;

    public GroupActionEventHandler(IGameLanguageService language, ISessionManager sessionManager, IInvitationManager invitation, IGroupFactory groupFactory)
    {
        _sessionManager = sessionManager;
        _invitation = invitation;
        _groupFactory = groupFactory;
        _language = language;
    }

    public async Task HandleAsync(GroupActionEvent e, CancellationToken cancellation)
    {
        IClientSession session = e.Sender;

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

        IClientSession sender;
        switch (e.RequestType)
        {
            case GroupRequestType.Requested:
            case GroupRequestType.Invited:
                if (session.PlayerEntity.IsInGroup() && session.PlayerEntity.IsGroupFull())
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_FULL, session.UserLanguage));
                    return;
                }

                if (session.PlayerEntity.Id == e.CharacterId)
                {
                    return;
                }

                if (session.PlayerEntity.IsInRaidParty)
                {
                    return;
                }

                if (session.PlayerEntity.HasRaidStarted)
                {
                    return;
                }

                IClientSession target = _sessionManager.GetSessionByCharacterId(e.CharacterId);
                if (target == null)
                {
                    return;
                }

                if (session.PlayerEntity.IsBlocking(e.CharacterId))
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.BLACKLIST_INFO_BLOCKING, session.UserLanguage));
                    return;
                }

                if (target.PlayerEntity.IsBlocking(session.PlayerEntity.Id))
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.BLACKLIST_INFO_BLOCKED, session.UserLanguage));
                    return;
                }

                if (session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4))
                {
                    if (session.PlayerEntity.IsSeal)
                    {
                        return;
                    }

                    if (target.PlayerEntity.Faction != session.PlayerEntity.Faction)
                    {
                        return;
                    }
                }

                if (target.PlayerEntity.GroupRequestBlocked)
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_BLOCKED, session.UserLanguage));
                    return;
                }

                if (session.PlayerEntity.IsInGroup() && target.PlayerEntity.IsInGroup())
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_ALREADY_IN_GROUP, session.UserLanguage));
                    return;
                }

                if (target.PlayerEntity.IsInRaidParty)
                {
                    return;
                }

                if (target.PlayerEntity.HasRaidStarted)
                {
                    return;
                }

                if (_invitation.ContainsPendingInvitation(session.PlayerEntity.Id, target.PlayerEntity.Id, InvitationType.Group))
                {
                    _invitation.RemovePendingInvitation(session.PlayerEntity.Id, target.PlayerEntity.Id, InvitationType.Group);
                }

                await session.EmitEventAsync(new InvitationEvent(target.PlayerEntity.Id, InvitationType.Group));
                session.SendInfo(_language.GetLanguageFormat(GameDialogKey.GROUP_INFO_REQUEST, session.UserLanguage, target.PlayerEntity.Name));
                break;
            case GroupRequestType.Accepted:
                if (session.PlayerEntity.Id == e.CharacterId)
                {
                    return;
                }

                sender = _sessionManager.GetSessionByCharacterId(e.CharacterId);
                if (sender == null)
                {
                    return;
                }

                if (!_invitation.ContainsPendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.Group))
                {
                    return;
                }

                _invitation.RemovePendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.Group);

                if (session.PlayerEntity.IsBlocking(e.CharacterId))
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.BLACKLIST_INFO_BLOCKING, session.UserLanguage));
                    return;
                }

                if (sender.PlayerEntity.IsBlocking(session.PlayerEntity.Id))
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.BLACKLIST_INFO_BLOCKED, session.UserLanguage));
                    return;
                }

                if (session.PlayerEntity.IsInGroup() && sender.PlayerEntity.IsInGroup())
                {
                    session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_ALREADY_IN_GROUP, session.UserLanguage));
                    return;
                }

                if (sender.PlayerEntity.IsInRaidParty)
                {
                    return;
                }

                if (sender.PlayerEntity.HasRaidStarted)
                {
                    return;
                }

                if (session.PlayerEntity.IsInRaidParty)
                {
                    return;
                }

                if (session.PlayerEntity.HasRaidStarted)
                {
                    return;
                }

                if (session.PlayerEntity.IsInGroup())
                {
                    if (session.PlayerEntity.IsGroupFull())
                    {
                        session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_FULL, session.UserLanguage));
                        return;
                    }

                    PlayerGroup grp = session.PlayerEntity.GetGroup();
                    await sender.EmitEventAsync(new JoinToGroupEvent(grp));
                    await session.EmitEventAsync(new GroupAddMemberEvent(sender.PlayerEntity));
                    sender.SendInfo(session.GetLanguageFormat(GameDialogKey.GROUP_INFO_JOIN, session.PlayerEntity.Name));

                    foreach (IPlayerEntity player in grp.Members)
                    {
                        if (player.MapInstance is not { MapInstanceType: MapInstanceType.ArenaInstance })
                        {
                            continue;
                        }

                        player.Session.SendArenaStatistics(false, grp);
                    }

                    return;
                }

                if (!sender.PlayerEntity.IsInGroup())
                {
                    var members = new List<IPlayerEntity> { sender.PlayerEntity, session.PlayerEntity };
                    PlayerGroup newPlayerGroup = _groupFactory.CreateGroup(3, members, sender.PlayerEntity.Id);
                    await sender.EmitEventAsync(new JoinToGroupEvent(newPlayerGroup));
                    await session.EmitEventAsync(new JoinToGroupEvent(newPlayerGroup));

                    sender.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_ADMIN, sender.UserLanguage));
                    session.SendInfo(session.GetLanguageFormat(GameDialogKey.GROUP_INFO_JOIN, sender.PlayerEntity.Name));

                    foreach (IPlayerEntity player in members)
                    {
                        if (player.MapInstance is not { MapInstanceType: MapInstanceType.ArenaInstance })
                        {
                            continue;
                        }

                        player.Session.SendArenaStatistics(false, newPlayerGroup);
                    }

                    return;
                }

                if (sender.PlayerEntity.IsGroupFull())
                {
                    session.SendInfo(session.GetLanguage(GameDialogKey.GROUP_INFO_FULL));
                    return;
                }

                PlayerGroup getPlayerGroup = sender.PlayerEntity.GetGroup();
                await session.EmitEventAsync(new JoinToGroupEvent(getPlayerGroup));
                await sender.EmitEventAsync(new GroupAddMemberEvent(session.PlayerEntity));
                session.SendInfo(session.GetLanguageFormat(GameDialogKey.GROUP_INFO_JOIN, sender.PlayerEntity.Name));

                foreach (IPlayerEntity player in getPlayerGroup.Members)
                {
                    if (player.MapInstance is not { MapInstanceType: MapInstanceType.ArenaInstance })
                    {
                        continue;
                    }

                    player.Session.SendArenaStatistics(false, getPlayerGroup);
                }

                break;
            case GroupRequestType.Declined:
                if (session.PlayerEntity.IsInGroup())
                {
                    return;
                }

                if (session.PlayerEntity.Id == e.CharacterId)
                {
                    return;
                }

                sender = _sessionManager.GetSessionByCharacterId(e.CharacterId);
                if (sender == null)
                {
                    return;
                }

                if (!_invitation.ContainsPendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.Group))
                {
                    return;
                }

                sender.SendChatMessage(string.Format(
                    _language.GetLanguage(GameDialogKey.GROUP_CHATMESSAGE_REQUEST_REFUSED, sender.UserLanguage), session.PlayerEntity.Name), ChatMessageColorType.Yellow);

                _invitation.RemovePendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.Group);
                break;
            case GroupRequestType.Sharing:

                if (!session.PlayerEntity.IsInGroup())
                {
                    return;
                }

                if (session.PlayerEntity.HomeComponent.Return == null || session.PlayerEntity.HomeComponent.Return.MapId == 0)
                {
                    return;
                }

                foreach (IPlayerEntity member in session.PlayerEntity.GetGroup().Members)
                {
                    if (member.Id == session.PlayerEntity.Id)
                    {
                        continue;
                    }

                    await session.EmitEventAsync(new InvitationEvent(member.Id, InvitationType.GroupPointShare));
                }

                session.SendInfo(_language.GetLanguage(GameDialogKey.GROUP_INFO_SHARE_POINT_TO_MEMBERS, session.UserLanguage));
                break;
            case GroupRequestType.AcceptedShare:

                if (!session.PlayerEntity.IsInGroup())
                {
                    return;
                }

                sender = _sessionManager.GetSessionByCharacterId(e.CharacterId);
                if (sender == null)
                {
                    return;
                }

                if (!sender.PlayerEntity.IsInGroup())
                {
                    return;
                }

                if (session.PlayerEntity.GetGroupId() != sender.PlayerEntity.GetGroupId())
                {
                    return;
                }

                if (!_invitation.ContainsPendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.GroupPointShare))
                {
                    return;
                }

                await session.EmitEventAsync(new ReturnChangeEvent
                {
                    MapId = sender.PlayerEntity.HomeComponent.Return.MapId,
                    MapX = sender.PlayerEntity.HomeComponent.Return.MapX,
                    MapY = sender.PlayerEntity.HomeComponent.Return.MapY,
                    IsByGroup = true
                });

                _invitation.RemovePendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.GroupPointShare);
                sender.SendMsg(_language.GetLanguageFormat(GameDialogKey.GROUP_SHOUTMESSAGE_SHARE_POINT_ACCEPTED, sender.UserLanguage, session.PlayerEntity.Name), MsgMessageType.Middle);
                session.SendMsg(_language.GetLanguage(GameDialogKey.GROUP_SHOUTMESSAGE_SHARE_POINT_YOU_ACCEPTED, session.UserLanguage), MsgMessageType.Middle);
                break;
            case GroupRequestType.DeclinedShare:

                if (!session.PlayerEntity.IsInGroup())
                {
                    return;
                }

                sender = _sessionManager.GetSessionByCharacterId(e.CharacterId);
                if (sender == null)
                {
                    return;
                }

                if (!sender.PlayerEntity.IsInGroup())
                {
                    return;
                }

                if (session.PlayerEntity.GetGroupId() != sender.PlayerEntity.GetGroupId())
                {
                    return;
                }

                if (!_invitation.ContainsPendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.GroupPointShare))
                {
                    return;
                }

                _invitation.RemovePendingInvitation(sender.PlayerEntity.Id, session.PlayerEntity.Id, InvitationType.GroupPointShare);

                sender.SendMsg(_language.GetLanguageFormat(GameDialogKey.GROUP_SHOUTMESSAGE_SHARE_POINT_DECLINED, sender.UserLanguage, session.PlayerEntity.Name), MsgMessageType.Middle);
                session.SendMsg(_language.GetLanguage(GameDialogKey.GROUP_SHOUTMESSAGE_SHARE_POINT_YOU_DECLINED, session.UserLanguage), MsgMessageType.Middle);
                break;
        }
    }
}