// 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 Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database.Repositories;
using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services;
using Remora.Discord.API;
using Remora.Discord.API.Abstractions.Gateway.Events;
using Remora.Discord.Extensions.Embeds;
using Remora.Discord.Gateway.Responders;
using Remora.Results;

namespace Catalogger.Backend.Bot.Responders.Guilds;

public class GuildUpdateResponder(
    ILogger logger,
    GuildRepository guildRepository,
    GuildCache guildCache,
    UserCache userCache,
    WebhookExecutorService webhookExecutor
) : IResponder<IGuildUpdate>
{
    private readonly ILogger _logger = logger.ForContext<GuildUpdateResponder>();

    public async Task<Result> RespondAsync(IGuildUpdate evt, CancellationToken ct = default)
    {
        try
        {
            if (!guildCache.TryGet(evt.ID, out var oldGuild))
            {
                _logger.Warning(
                    "Guild {GuildId} not found in cache, ignoring event and adding it to cache",
                    evt.ID
                );
                return Result.Success;
            }

            var embed = new EmbedBuilder()
                .WithTitle("Server updated")
                .WithColour(DiscordUtils.Blue)
                .WithCurrentTimestamp();

            if (evt.Name != oldGuild.Name)
                embed.AddField("Name", $"**Before:** {oldGuild.Name}\n**After:** {evt.Name}");

            if (!Equals(evt.Icon, oldGuild.Icon))
            {
                if (evt.Icon != null)
                    embed.WithThumbnailUrl(
                        CDN.GetGuildIconUrl(evt, imageSize: 1024).GetOrThrow().ToString()
                    );

                if (evt.Icon != null && oldGuild.Icon == null)
                {
                    embed.AddField(
                        "Icon added",
                        $"[Link]({CDN.GetGuildIconUrl(evt, imageSize: 1024).GetOrThrow()})"
                    );
                }
                else if (evt.Icon != null && oldGuild.Icon != null)
                {
                    embed.AddField(
                        "Icon changed",
                        $"[Link]({CDN.GetGuildIconUrl(evt, imageSize: 1024).GetOrThrow()})"
                    );
                }
                else
                {
                    embed.AddField("Icon removed", "*(old icon no longer available, sorry)*");
                }
            }

            if (evt.OwnerID != oldGuild.OwnerID)
            {
                embed.AddField(
                    "Ownership transferred",
                    $"""
                    **Before:** {userCache.TryFormatUserAsync(oldGuild.OwnerID)}
                    **After:** {userCache.TryFormatUserAsync(evt.OwnerID)}
                    """
                );
            }

            if (embed.Fields.Count != 0)
            {
                var guildConfig = await guildRepository.GetAsync(evt.ID);
                webhookExecutor.QueueLog(
                    guildConfig,
                    LogChannelType.GuildUpdate,
                    embed.Build().GetOrThrow()
                );
            }
            else
            {
                _logger.Debug(
                    "Guild update event for {GuildId} had nothing we want to log, not sending embed",
                    evt.ID
                );
            }

            return Result.Success;
        }
        finally
        {
            guildCache.Set(evt);
        }
    }
}
