using EllieBot.Modules.Patronage;

namespace EllieBot.Modules.Help;

public partial class Help
{
    [OnlyPublicBot]
    public partial class Patronage : EllieModule
    {
        private readonly PatronageService _service;
        private readonly PatronageConfig _pConf;

        public Patronage(PatronageService service, PatronageConfig pConf)
        {
            _service = service;
            _pConf = pConf;
        }

        [Cmd]
        [Priority(2)]
        public Task Patron()
            => InternalPatron(ctx.User);

        [Cmd]
        [Priority(0)]
        [OwnerOnly]
        public Task Patron(IUser user)
            => InternalPatron(user);

        [Cmd]
        [Priority(0)]
        [OwnerOnly]
        public async Task PatronMessage(PatronTier tierAndHigher, string message)
        {
            _ = ctx.Channel.TriggerTypingAsync();
            var result = await _service.SendMessageToPatronsAsync(tierAndHigher, message);

            await Response()
                  .Confirm(strs.patron_msg_sent(
                      Format.Code(tierAndHigher.ToString()),
                      Format.Bold(result.Success.ToString()),
                      Format.Bold(result.Failed.ToString())))
                  .SendAsync();
        }

        // [OwnerOnly]
        // public async Task PatronGift(IUser user, int amount)
        // {
        //     // i can't figure out a good way to gift more than one month at the moment.
        //
        //     if (amount < 1)
        //         return;
        //     
        //     var patron = _service.GiftPatronAsync(user, amount);
        //
        //     var eb = CreateEmbed();
        //
        //     await Response().Embed(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!")
        //                                    .AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
        //                                    .AddField("Amount", $"**{patron.Amount / 100.0f:N1}$**", true)
        //                                    .AddField("Until", TimestampTag.FromDateTime(patron.ValidThru.AddDays(1)))).SendAsync();
        //     
        //
        // }

        private async Task InternalPatron(IUser user)
        {
            if (!_pConf.Data.IsEnabled)
            {
                await Response().Error(strs.patron_not_enabled).SendAsync();
                return;
            }

            var maybePatron = await _service.GetPatronAsync(user.Id);

            var quotaStats = await _service.LimitStats(user.Id);

            var eb = CreateEmbed()
                            .WithAuthor(user)
                            .WithTitle(GetText(strs.patron_info))
                            .WithOkColor();

            if (quotaStats.Count == 0 || maybePatron is not { } patron)
            {
                eb.WithDescription(GetText(strs.no_quota_found));
            }
            else
            {
                eb.AddField(GetText(strs.tier), Format.Bold(patron.Tier.ToFullName()), true)
                  .AddField(GetText(strs.pledge), $"**{patron.Amount / 100.0f:N1}$**", true);

                if (patron.Tier != PatronTier.None)
                    eb.AddField(GetText(strs.expires),
                        patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
                        true);

                eb.AddField(GetText(strs.quotas), "⁣", false);

                var text = GetQuotaList(quotaStats);
                if (!string.IsNullOrWhiteSpace(text))
                    eb.AddField(GetText(strs.modules), text, true);
            }


            try
            {
                await Response().User(ctx.User).Embed(eb).SendAsync();
                _ = ctx.OkAsync();
            }
            catch
            {
                await Response().Error(strs.cant_dm).SendAsync();
            }
        }

        private string GetQuotaList(
            IReadOnlyDictionary<LimitedFeatureName, (int Cur, QuotaLimit Quota)> featureQuotaStats)
        {
            var text = string.Empty;
            foreach (var (key, (cur, quota)) in featureQuotaStats)
            {
                text += $"\n⁣\t`{key}`\n";
                if (quota.QuotaPeriod == QuotaPer.PerHour)
                    text += $"⁣ ⁣  {cur}/{(quota.Quota == -1 ? "∞" : quota.Quota)} {QuotaPeriodToString(quota.QuotaPeriod)}\n";
            }

            return text;
        }

        public string QuotaPeriodToString(QuotaPer per)
            => per switch
            {
                QuotaPer.PerHour => "per hour",
                QuotaPer.PerDay => "per day",
                QuotaPer.PerMonth => "per month",
                QuotaPer.Total => "total",
                _ => throw new ArgumentOutOfRangeException(nameof(per), per, null)
            };
    }
}