// 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.InMemoryCache;
using Catalogger.Backend.Database.Repositories;
using Catalogger.Backend.Extensions;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.Commands.Feedback.Services;
using Remora.Discord.Commands.Services;
using Remora.Discord.Extensions.Embeds;
using IResult = Remora.Results.IResult;

namespace Catalogger.Backend.Bot.Commands;

public partial class IgnoreMessageCommands
{
    [Group("roles")]
    public class Roles(
        GuildRepository guildRepository,
        GuildCache guildCache,
        RoleCache roleCache,
        ContextInjectionService contextInjection,
        FeedbackService feedbackService
    ) : CommandGroup
    {
        [Command("add")]
        [Description("Add a role to the list of ignored roles.")]
        public async Task<IResult> AddIgnoredRoleAsync(
            [Description("The role to ignore")] IRole role
        )
        {
            var (_, guildId) = contextInjection.GetUserAndGuild();
            var guildConfig = await guildRepository.GetAsync(guildId);

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

            guildConfig.Messages.IgnoredRoles.Add(role.ID.Value);
            await guildRepository.UpdateConfigAsync(guildId, guildConfig);

            return await feedbackService.ReplyAsync(
                $"Successfully added {role.Name} to the list of ignored roles."
            );
        }

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

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

            guildConfig.Messages.IgnoredRoles.Remove(role.ID.Value);
            await guildRepository.UpdateConfigAsync(guildId, guildConfig);

            return await feedbackService.ReplyAsync(
                $"Successfully removed {role.Name} from the list of ignored roles."
            );
        }

        [Command("list")]
        [Description("List roles ignored for logging.")]
        public async Task<IResult> ListIgnoredRolesAsync()
        {
            var (_, guildId) = contextInjection.GetUserAndGuild();
            if (!guildCache.TryGet(guildId, out var guild))
                throw new CataloggerError("Guild not in cache");

            var guildConfig = await guildRepository.GetAsync(guildId);

            var roles = roleCache
                .GuildRoles(guildId)
                .Where(r => guildConfig.Messages.IgnoredRoles.Contains(r.ID.Value))
                .OrderByDescending(r => r.Position)
                .Select(r => $"<@&{r.ID}>")
                .ToList();
            if (roles.Count == 0)
                return await feedbackService.ReplyAsync(
                    "No roles are being ignored right now.",
                    isEphemeral: true
                );

            return await feedbackService.ReplyAsync(
                embeds:
                [
                    new EmbedBuilder()
                        .WithTitle($"Ignored roles in {guild.Name}")
                        .WithDescription(string.Join("\n", roles))
                        .WithColour(DiscordUtils.Purple)
                        .Build()
                        .GetOrThrow(),
                ]
            );
        }
    }
}
