using System;
using System.Threading.Tasks;
using WingsAPI.Game.Extensions.ItemExtension.Inventory;
using WingsEmu.Core.Extensions;
using WingsEmu.DTOs.Maps;
using WingsEmu.DTOs.Respawns;
using WingsEmu.Game._enum;
using WingsEmu.Game._i18n;
using WingsEmu.Game._ItemUsage;
using WingsEmu.Game._ItemUsage.Event;
using WingsEmu.Game.Act4;
using WingsEmu.Game.Battle;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Helpers;
using WingsEmu.Game.Items;
using WingsEmu.Game.Managers;
using WingsEmu.Game.Maps;
using WingsEmu.Game.Networking;
using WingsEmu.Game.RespawnReturn.Event;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Chat;

namespace WingsEmu.Plugins.BasicImplementations.ItemUsage.Etc.Magical;

/// <summary>
///     This handler is used for Return Wing, Return Amulet, Return Scroll, Miniland Bell, Lod Scroll
/// </summary>
public class TeleportationItemHandler : IItemHandler
{
    private const int ReturnWing = 0;
    private const int ReturnAmulet = 1;
    private const int MinilandBell = 2;
    private const int LodScroll = 4;
    private const int BaseTeleporter = 5;
    private const int ReturnScroll = 6;
    private readonly IAct4FlagManager _act4FlagManager;

    private readonly IDelayManager _delayManager;
    private readonly IGameLanguageService _languageService;
    private readonly IMapManager _mapManager;

    public TeleportationItemHandler(IGameLanguageService languageService, IDelayManager delayManager, IAct4FlagManager act4FlagManager, IMapManager mapManager)
    {
        _languageService = languageService;
        _delayManager = delayManager;
        _act4FlagManager = act4FlagManager;
        _mapManager = mapManager;
    }

    public ItemType ItemType => ItemType.Magical;
    public long[] Effects => new long[] { 1 };

    public async Task HandleAsync(IClientSession session, InventoryUseItemEvent e)
    {
        IGameItem gameItem = e.Item.ItemInstance.GameItem;

        if (session.PlayerEntity.IsOnVehicle)
        {
            session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ITEM_CHATMESSAGE_CANT_USE_THAT, session.UserLanguage), ChatMessageColorType.Yellow);
            return;
        }

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

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

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

        switch (gameItem.EffectValue)
        {
            /*
             * RETURN WING & RETURN SCROLL (ACT 5)
             */
            case ReturnWing or ReturnScroll when session.CantPerformActionOnAct4():
                return;
            case ReturnWing or ReturnScroll:
            {
                DelayedActionType actionType = gameItem.EffectValue == ReturnWing ? DelayedActionType.ReturnWing : DelayedActionType.ReturnScroll;

                bool isAct5Map = session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_5_1) || session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_5_2);

                if (isAct5Map && gameItem.EffectValue == ReturnWing || !isAct5Map && gameItem.EffectValue == ReturnScroll)
                {
                    session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ITEM_CHATMESSAGE_CANT_USE_THAT, session.UserLanguage), ChatMessageColorType.Yellow);
                    return;
                }

                if (e.Option == 0)
                {
                    session.SendDialog(
                        $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} 1",
                        $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} 2",
                        _languageService.GetLanguage(GameDialogKey.ITEM_DIALOG_WANT_TO_SAVE_POSITION, session.UserLanguage));
                    return;
                }

                if (!int.TryParse(e.Packet[6], out int usageType))
                {
                    return;
                }

                switch (usageType)
                {
                    case 1:
                    // 1 - Save position, 2 - Don't save position
                    case 2:
                    {
                        DateTime targetTime = await _delayManager.RegisterAction(session.PlayerEntity, actionType);
                        session.SendDelay(targetTime.GetTotalMillisecondUntilNow(), GuriType.UsingItem,
                            $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} {(usageType == 1 ? 3 : 4)}");
                        return;
                    }
                    case 3:
                    case 4:
                    {
                        bool canPerformAction = await _delayManager.CanPerformAction(session.PlayerEntity, actionType);
                        if (!canPerformAction)
                        {
                            return;
                        }

                        if (!session.PlayerEntity.MapInstance.HasMapFlag(MapFlags.IS_BASE_MAP))
                        {
                            session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ITEM_CHATMESSAGE_CANT_USE_THAT, session.UserLanguage), ChatMessageColorType.Yellow);
                            return;
                        }

                        await _delayManager.CompleteAction(session.PlayerEntity, actionType);

                        if (usageType == 3 && session.PlayerEntity.MapId != 10000)
                        {
                            await session.EmitEventAsync(new ReturnChangeEvent
                            {
                                MapId = session.PlayerEntity.MapId,
                                MapX = session.PlayerEntity.PositionX,
                                MapY = session.PlayerEntity.PositionY
                            });
                        }

                        await session.Respawn();

                        await session.RemoveItemFromInventory(item: e.Item);
                        break;
                    }
                }

                return;
            }
            /*
         * RETURN AMULET
         */
            case ReturnAmulet when session.CantPerformActionOnAct4():
                return;
            case ReturnAmulet:
            {
                if (!int.TryParse(e.Packet[6], out int usageType))
                {
                    return;
                }

                if (!session.PlayerEntity.MapInstance.HasMapFlag(MapFlags.IS_BASE_MAP))
                {
                    session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ITEM_CHATMESSAGE_CANT_USE_THAT, session.UserLanguage), ChatMessageColorType.Yellow);
                    return;
                }

                CharacterReturnDto returnPoint = session.PlayerEntity.HomeComponent.Return;

                if (returnPoint == null)
                {
                    session.PlayerEntity.HomeComponent.ChangeReturn(new CharacterReturnDto());
                    return;
                }

                IMapInstance returnMap = _mapManager.GetBaseMapInstanceByMapId(returnPoint.MapId);

                if (returnPoint.MapId != 0 && returnMap != null)
                {
                    bool isAct5 = returnMap.HasMapFlag(MapFlags.ACT_5_1) || returnMap.HasMapFlag(MapFlags.ACT_5_2);
                    if (!session.IsInAct5() && isAct5)
                    {
                        session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ACT5_MESSAGE_RETURN_DISABLED, session.UserLanguage), ChatMessageColorType.Yellow);
                        return;
                    }

                    if (session.IsInAct5() && !isAct5)
                    {
                        session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ACT5_MESSAGE_RETURN_DISABLED, session.UserLanguage), ChatMessageColorType.Yellow);
                        return;
                    }
                }

                switch (usageType)
                {
                    case 0:
                    {
                        if (returnPoint.MapId == 0)
                        {
                            return;
                        }

                        session.SendRpPacket(returnPoint.MapId, returnPoint.MapX, returnPoint.MapY, $"#u_i^2^{session.PlayerEntity.Id}^{(byte)e.Item.ItemInstance.GameItem.Type}^{e.Item.Slot}^1");
                        return;
                    }
                    case 1:
                    {
                        DateTime targetTime = await _delayManager.RegisterAction(session.PlayerEntity, DelayedActionType.ReturnAmulet);
                        session.SendDelay(targetTime.GetTotalMillisecondUntilNow(), GuriType.UsingItem, $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} 2");
                        return;
                    }
                    case 2:
                    {
                        bool canUseReturnAmulet = await _delayManager.CanPerformAction(session.PlayerEntity, DelayedActionType.ReturnAmulet);
                        if (!canUseReturnAmulet)
                        {
                            return;
                        }

                        await _delayManager.CompleteAction(session.PlayerEntity, DelayedActionType.ReturnAmulet);

                        if (returnPoint.MapId == 0)
                        {
                            return;
                        }

                        session.ChangeMap(returnPoint.MapId, returnPoint.MapX, returnPoint.MapY);
                        await session.RemoveItemFromInventory(item: e.Item);
                        break;
                    }
                }

                return;
            }
            case BaseTeleporter:
                if (!session.PlayerEntity.MapInstance.HasMapFlag(MapFlags.ACT_4))
                {
                    return;
                }

                if (!session.PlayerEntity.MapInstance.HasMapFlag(MapFlags.IS_BASE_MAP))
                {
                    return;
                }

                if (e.Option == 0)
                {
                    DateTime targetTime = await _delayManager.RegisterAction(session.PlayerEntity, DelayedActionType.BaseTeleporter);
                    session.SendDelay(targetTime.GetTotalMillisecondUntilNow(), GuriType.UsingItem, $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} 1");
                    return;
                }

                bool canPerformActionAction = await _delayManager.CanPerformAction(session.PlayerEntity, DelayedActionType.BaseTeleporter);
                if (!canPerformActionAction)
                {
                    return;
                }

                await _delayManager.CompleteAction(session.PlayerEntity, DelayedActionType.BaseTeleporter);

                FactionType faction = session.PlayerEntity.Faction;
                MapLocation map = faction == FactionType.Angel ? _act4FlagManager.AngelFlag : _act4FlagManager.DemonFlag;
                if (map == null)
                {
                    return;
                }

                session.ChangeMap(map.MapInstanceId, map.X, map.Y);
                await session.RemoveItemFromInventory(item: e.Item);

                break;
            /*
         * MINILAND BELL & LOD SCROLL
         */
            case MinilandBell:
            case LodScroll:
            {
                if (!session.PlayerEntity.MapInstance.HasMapFlag(MapFlags.IS_BASE_MAP))
                {
                    session.SendChatMessage(_languageService.GetLanguage(GameDialogKey.ITEM_CHATMESSAGE_CANT_USE_THAT, session.UserLanguage), ChatMessageColorType.Yellow);
                    return;
                }

                DelayedActionType actionType = gameItem.EffectValue == MinilandBell ? DelayedActionType.MinilandBell : DelayedActionType.LodScroll;
                if (e.Option == 0)
                {
                    DateTime targetTime = await _delayManager.RegisterAction(session.PlayerEntity, actionType);
                    session.SendDelay(targetTime.GetTotalMillisecondUntilNow(), GuriType.UsingItem, $"u_i 2 {session.PlayerEntity.Id} {(byte)e.Item.ItemInstance.GameItem.Type} {e.Item.Slot} 1");
                    return;
                }

                bool canPerformAction = await _delayManager.CanPerformAction(session.PlayerEntity, actionType);
                if (!canPerformAction)
                {
                    return;
                }

                await _delayManager.CompleteAction(session.PlayerEntity, actionType);

                if (actionType != DelayedActionType.MinilandBell)
                {
                    return;
                }

                if (session.CurrentMapInstance.HasMapFlag(MapFlags.ACT_4))
                {
                    bool canEnter = session.PlayerEntity.Faction switch
                    {
                        FactionType.Angel => session.CurrentMapInstance.MapId == (int)MapIds.ACT4_ANGEL_CITADEL,
                        FactionType.Demon => session.CurrentMapInstance.MapId == (int)MapIds.ACT4_DEMON_CITADEL,
                        _ => false
                    };

                    if (!canEnter)
                    {
                        session.SendMsg(_languageService.GetLanguage(GameDialogKey.INFORMATION_SHOUTMESSAGE_MUST_BE_IN_CLASSIC_MAP, session.UserLanguage), MsgMessageType.Middle);
                        return;
                    }
                }

                session.ChangeMap(session.PlayerEntity.Miniland);
                await session.RemoveItemFromInventory(item: e.Item);
                break;
            }
        }
    }
}