// 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.Net;
using Catalogger.Backend.Api.Middleware;
using Catalogger.Backend.Database.Models;
using Microsoft.AspNetCore.Mvc;
using NodaTime;
using Remora.Discord.API;

namespace Catalogger.Backend.Api;

public partial class GuildsController
{
    [Authorize]
    [HttpGet("config")]
    public async Task<IActionResult> ExportConfigAsync(string id)
    {
        var (guildId, _) = await ParseGuildAsync(id);
        var guildConfig = await guildRepository.GetAsync(guildId);

        return Ok(await ToExport(guildConfig));
    }

    [Authorize]
    [HttpPost("config")]
    public async Task<IActionResult> ImportConfigAsync(string id, [FromBody] ConfigExport export)
    {
        var (guildId, _) = await ParseGuildAsync(id);
        if (export.Id != guildId.Value)
            throw new ApiError(
                HttpStatusCode.BadRequest,
                ErrorCode.BadRequest,
                "This backup is not from this server."
            );

        // Filter invites to *only* those that exist for this guild.
        // Blame past me for not making (code, guild_id) a unique index >:|
        var cachedInvites = (await inviteCache.TryGetAsync(guildId)).ToList();
        var invites = export.Invites.Where(i => cachedInvites.Any(ci => i.Code == ci.Code));

        await guildRepository.ImportConfigAsync(
            guildId.Value,
            export.Channels.ToChannelConfig(),
            export.Channels.ToMessageConfig(),
            export.BannedSystems,
            export.KeyRoles
        );

        await inviteRepository.ImportInvitesAsync(
            guildId,
            invites.Select(i => new Invite
            {
                Code = i.Code,
                Name = i.Name,
                GuildId = guildId.Value,
            })
        );

        await watchlistRepository.ImportWatchlistAsync(
            guildId,
            export.Watchlist.Select(w => new Watchlist
            {
                GuildId = guildId.Value,
                UserId = w.UserId,
                ModeratorId = w.ModeratorId,
                AddedAt = w.AddedAt,
                Reason = w.Reason,
            })
        );

        return NoContent();
    }

    private async Task<ConfigExport> ToExport(Database.Models.Guild config)
    {
        var id = DiscordSnowflake.New(config.Id);
        var invites = await inviteRepository.GetGuildInvitesAsync(id);
        var watchlist = await watchlistRepository.GetGuildWatchlistAsync(id);

        return new ConfigExport(
            config.Id,
            ChannelsBackup.FromGuildConfig(config),
            config.BannedSystems,
            config.KeyRoles,
            invites.Select(i => new InviteExport(i.Code, i.Name)),
            watchlist.Select(w => new WatchlistExport(w.UserId, w.AddedAt, w.ModeratorId, w.Reason))
        );
    }
}
