// Copyright (C) 2021-present sam (starshines.gay)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

using System.ComponentModel;
using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database.Repositories;
using Catalogger.Backend.Extensions;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
using Remora.Discord.API;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.Commands.Feedback.Services;
using Remora.Discord.Commands.Services;
using Remora.Discord.Pagination.Extensions;
using Remora.Rest.Core;
using IResult = Remora.Results.IResult;

namespace Catalogger.Backend.Bot.Commands;

public partial class IgnoreMessageCommands
{
    [Group("users")]
    public class Users(
        GuildRepository guildRepository,
        IMemberCache memberCache,
        GuildCache guildCache,
        UserCache userCache,
        ContextInjectionService contextInjection,
        FeedbackService feedbackService
    ) : CommandGroup
    {
        [Command("add")]
        [Description("Add a user to the list of ignored users.")]
        public async Task<IResult> AddIgnoredUserAsync(
            [Description("The user to ignore")] IUser user
        )
        {
            var (_, guildId) = contextInjection.GetUserAndGuild();
            var guildConfig = await guildRepository.GetAsync(guildId);

            if (guildConfig.Messages.IgnoredUsers.Contains(user.ID.Value))
                return await feedbackService.ReplyAsync(
                    "That user is already being ignored.",
                    isEphemeral: true
                );

            guildConfig.Messages.IgnoredUsers.Add(user.ID.Value);
            await guildRepository.UpdateConfigAsync(guildId, guildConfig);

            return await feedbackService.ReplyAsync(
                $"Successfully added {user.PrettyFormat()} to the list of ignored users."
            );
        }

        [Command("remove")]
        [Description("Remove a user from the list of ignored users.")]
        public async Task<IResult> RemoveIgnoredUserAsync(
            [Description("The user to stop ignoring")] IUser user
        )
        {
            var (_, guildId) = contextInjection.GetUserAndGuild();
            var guildConfig = await guildRepository.GetAsync(guildId);

            if (!guildConfig.Messages.IgnoredUsers.Contains(user.ID.Value))
                return await feedbackService.ReplyAsync(
                    "That user is already not ignored.",
                    isEphemeral: true
                );

            guildConfig.Messages.IgnoredUsers.Remove(user.ID.Value);
            await guildRepository.UpdateConfigAsync(guildId, guildConfig);

            return await feedbackService.ReplyAsync(
                $"Successfully removed {user.PrettyFormat()} from the list of ignored users."
            );
        }

        [Command("list")]
        [Description("List currently ignored users.")]
        public async Task<IResult> ListIgnoredUsersAsync()
        {
            var (userId, guildId) = contextInjection.GetUserAndGuild();
            if (!guildCache.TryGet(guildId, out var guild))
                throw new CataloggerError("Guild was not cached");

            var guildConfig = await guildRepository.GetAsync(guildId);

            if (guildConfig.Messages.IgnoredUsers.Count == 0)
                return await feedbackService.ReplyAsync("No users are being ignored right now.");

            var users = new List<string>();
            foreach (var id in guildConfig.Messages.IgnoredUsers)
            {
                var user = await TryGetUserAsync(guildId, DiscordSnowflake.New(id));
                users.Add(user?.PrettyFormat() ?? $"*(unknown user {id})* <@{id}>");
            }

            return await feedbackService.SendContextualPaginatedMessageAsync(
                userId,
                DiscordUtils.PaginateStrings(
                    users,
                    $"Ignored users for {guild.Name} ({users.Count})"
                )
            );
        }

        private async Task<IUser?> TryGetUserAsync(Snowflake guildId, Snowflake userId) =>
            (await memberCache.TryGetAsync(guildId, userId))?.User.Value
            ?? await userCache.GetUserAsync(userId);
    }
}
