using EllieBot.Modules.Games.Fish.Db;

namespace EllieBot.Modules.Games;

public partial class Games
{
    public class FishItemCommands(FishItemService fis, ICurrencyProvider cp) : EllieModule
    {
        [Cmd]
        [RequireContext(ContextType.Guild)]
        public async Task FishShop()
        {
            var items = fis.GetItems();

            await Response()
                .Paginated()
                .Items(items)
                .PageSize(9)
                .CurrentPage(0)
                .Page((pageItems, i) =>
                {
                    var eb = CreateEmbed()
                        .WithTitle(GetText(strs.fish_items_title))
                        .WithFooter("`.fibuy <id>` to by an item")
                        .WithOkColor();

                    foreach (var item in pageItems)
                    {
                        var description = GetItemDescription(item);
                        eb.AddField($"{item.Id}",
                            $"""
                             {description}
                              
                             """,
                            true);
                    }

                    return eb;
                })
                .AddFooter(false)
                .SendAsync();
        }

        private string GetItemDescription(FishItem item, UserFishItem? userItem = null)
        {
            var multiplierInfo = GetMultiplierInfo(item);

            var priceText = userItem is null
                ? $"【 **{CurrencyHelper.N(item.Price, Culture, cp.GetCurrencySign())}** 】"
                : "";

            return $"""
                     《 **{item.Name}** 》
                     {GetEmoji(item.ItemType)} `{item.ItemType.ToString().ToLower()}` {priceText}
                     {item.Description}
                     {GetItemNotes(item, userItem)}
                     {multiplierInfo}
                    """;
        }

        private string GetItemNotes(FishItem item, UserFishItem? userItem)
        {
            var stats = new List<string>();

            if (item.Uses.HasValue)
                stats.Add($"**Uses:** {userItem?.UsesLeft ?? item.Uses}");

            if (item.DurationMinutes.HasValue)
                stats.Add($"**Duration:** {userItem?.ExpiryFromNowInMinutes() ?? item.DurationMinutes}m");

            var toReturn = stats.Count > 0 ? string.Join(" | ", stats) + "\n" : "\n";

            return "\n" + toReturn;
        }

        public static string GetEmoji(FishItemType itemType)
            => itemType switch
            {
                FishItemType.Pole => @"\🎣",
                FishItemType.Boat => @"\⛵",
                FishItemType.Bait => @"\🍥",
                FishItemType.Potion => @"\🍷",
                _ => ""
            };

        private string GetMultiplierInfo(FishItem item)
        {
            var multipliers = new FishMultipliers()
            {
                FishMultiplier = item.FishMultiplier ?? 1,
                TrashMultiplier = item.TrashMultiplier ?? 1,
                RareMultiplier = item.RareMultiplier ?? 1,
                StarMultiplier = item.MaxStarMultiplier ?? 1,
                FishingSpeedMultiplier = item.FishingSpeedMultiplier ?? 1
            };

            return GetMultiplierInfo(multipliers);
        }


        public static string GetMultiplierInfo(FishMultipliers item)
        {
            var multipliers = new List<string>();
            if (item.FishMultiplier is not 1.0d)
                multipliers.Add($"{AsPercent(item.FishMultiplier)} chance to catch fish");

            if (item.TrashMultiplier is not 1.0d)
                multipliers.Add($"{AsPercent(item.TrashMultiplier)} chance to catch trash");

            if (item.RareMultiplier is not 1.0d)
                multipliers.Add($"{AsPercent(item.RareMultiplier)} chance to catch rare fish");

            if (item.StarMultiplier is not 1.0d)
                multipliers.Add($"{AsPercent(item.StarMultiplier)} to max star rating");

            if (item.FishingSpeedMultiplier is not 1.0d)
                multipliers.Add($"{AsPercent(item.FishingSpeedMultiplier)} fishing speed");

            return multipliers.Count > 0
                ? $"{string.Join("\n", multipliers)}\n"
                : "";
        }

        private static string AsPercent(double multiplier)
        {
            var percentage = (int)((multiplier - 1.0f) * 100);
            return percentage >= 0 ? $"**+{percentage}%**" : $"**{percentage}%**";
        }


        [Cmd]
        [RequireContext(ContextType.Guild)]
        public async Task FishBuy(int itemId)
        {
            var res = await fis.BuyItemAsync(ctx.User.Id, itemId);

            if (res.TryPickT1(out var err, out var eqItem))
            {
                if (err == BuyResult.InsufficientFunds)
                    await Response().Error(strs.not_enough(cp.GetCurrencySign())).SendAsync();
                else
                    await Response().Error(strs.fish_item_not_found).SendAsync();

                return;
            }

            var embed = CreateEmbed()
                .WithDescription(GetText(strs.fish_buy_success))
                .AddField(eqItem.Name, GetMultiplierInfo(eqItem));

            await Response()
                .Embed(embed)
                .Interaction(_inter.Create(ctx.User.Id,
                    new ButtonBuilder("Inventory", Guid.NewGuid().ToString(), ButtonStyle.Secondary),
                    (smc) => FishInv()))
                .SendAsync();
        }

        [Cmd]
        [RequireContext(ContextType.Guild)]
        public async Task FishUse(int index)
        {
            var eqItem = await fis.EquipItemAsync(ctx.User.Id, index);

            if (eqItem is null)
            {
                await Response().Error(strs.fish_item_not_found).SendAsync();
                return;
            }

            var embed = CreateEmbed()
                .WithDescription(GetText(strs.fish_use_success))
                .AddField(eqItem.Name, GetMultiplierInfo(eqItem));

            await Response().Embed(embed).SendAsync();
        }

        [Cmd]
        [RequireContext(ContextType.Guild)]
        public async Task FishUnequip(FishItemType itemType)
        {
            var res = await fis.UnequipItemAsync(ctx.User.Id, itemType);

            if (res == UnequipResult.Success)
                await Response().Confirm(strs.fish_unequip_success).SendAsync();
            else if (res == UnequipResult.NotFound)
                await Response().Error(strs.fish_item_not_found).SendAsync();
            else
                await Response().Error(strs.fish_cant_uneq_potion).SendAsync();
        }

        [Cmd]
        [RequireContext(ContextType.Guild)]
        public async Task FishInv()
        {
            var userItems = await fis.GetUserItemsAsync(ctx.User.Id);

            await Response()
                .Paginated()
                .Items(userItems)
                .PageSize(9)
                .Page((items, page) =>
                {
                    page += 1;
                    var eb = CreateEmbed()
                        .WithAuthor(ctx.User)
                        .WithTitle(GetText(strs.fish_inv_title))
                        .WithFooter($"`.fiuse <num>` to use/equip an item")
                        .WithOkColor();

                    for (var i = 0; i < items.Count; i++)
                    {
                        var (userItem, item) = items[i];
                        var isEquipped = userItem.IsEquipped;

                        if (item is null)
                        {
                            eb.AddField($"{(page * 9) + i + 1} | Item not found", $"ID: {userItem.Id}", true);
                            continue;
                        }

                        var description = GetItemDescription(item, userItem);

                        if (isEquipped)
                            description = "🫴 **IN USE**\n" + description;

                        eb.AddField($"{i + 1} | {item.Name} ",
                            $"""
                             {description}
                             """,
                            true);
                    }

                    return eb;
                })
                .AddFooter(false)
                .SendAsync();
        }
    }
}