// 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.Extensions;
using Catalogger.Backend.Services;
using Remora.Rest.Core;

namespace Catalogger.Backend.Database.Models;

public class Guild
{
    public required ulong Id { get; init; }

    public ChannelConfig Channels { get; init; } = new();
    public MessageConfig Messages { get; init; } = new();
    public string[] BannedSystems { get; set; } = [];
    public List<ulong> KeyRoles { get; set; } = [];

    // These channels and roles are ignored for channel/role update/delete events.
    public List<ulong> IgnoredChannels { get; set; } = [];
    public List<ulong> IgnoredRoles { get; set; } = [];

    public bool IsSystemBanned(PluralkitApiService.PkSystem system) =>
        BannedSystems.Contains(system.Id) || BannedSystems.Contains(system.Uuid.ToString());

    public bool IsMessageIgnored(
        Snowflake channelId,
        Snowflake? userId,
        IReadOnlyList<Snowflake>? roleIds
    )
    {
        if (
            Channels is { MessageDelete: 0, MessageUpdate: 0, MessageDeleteBulk: 0 }
            || Messages.IgnoredChannels.Contains(channelId.ToUlong())
            || (userId != null && Messages.IgnoredUsers.Contains(userId.Value.ToUlong()))
            || (roleIds != null && roleIds.Any(r => Messages.IgnoredRoles.Any(id => r.Value == id)))
        )
            return true;

        if (userId == null)
            return false;

        if (
            Messages.IgnoredUsersPerChannel.TryGetValue(
                channelId.ToUlong(),
                out var thisChannelIgnoredUsers
            )
        )
            return thisChannelIgnoredUsers.Contains(userId.Value.ToUlong());

        return false;
    }

    public class MessageConfig
    {
        public List<ulong> IgnoredChannels { get; set; } = [];
        public List<ulong> IgnoredRoles { get; set; } = [];
        public List<ulong> IgnoredUsers { get; init; } = [];
        public Dictionary<ulong, List<ulong>> IgnoredUsersPerChannel { get; init; } = [];
    }

    public class ChannelConfig
    {
        public Dictionary<ulong, ulong> Redirects { get; init; } = [];

        public ulong GuildUpdate { get; set; }
        public ulong GuildEmojisUpdate { get; set; }
        public ulong GuildRoleCreate { get; set; }
        public ulong GuildRoleUpdate { get; set; }
        public ulong GuildRoleDelete { get; set; }
        public ulong ChannelCreate { get; set; }
        public ulong ChannelUpdate { get; set; }
        public ulong ChannelDelete { get; set; }
        public ulong GuildMemberAdd { get; set; }
        public ulong GuildMemberUpdate { get; set; }
        public ulong GuildKeyRoleUpdate { get; set; }
        public ulong GuildMemberNickUpdate { get; set; }
        public ulong GuildMemberAvatarUpdate { get; set; }
        public ulong GuildMemberTimeout { get; set; }
        public ulong GuildMemberRemove { get; set; }
        public ulong GuildMemberKick { get; set; }
        public ulong GuildBanAdd { get; set; }
        public ulong GuildBanRemove { get; set; }
        public ulong InviteCreate { get; set; }
        public ulong InviteDelete { get; set; }
        public ulong MessageUpdate { get; set; }
        public ulong MessageDelete { get; set; }
        public ulong MessageDeleteBulk { get; set; }

        private ulong[] _allUnfilteredChannels =>
            [
                GuildUpdate,
                GuildEmojisUpdate,
                GuildRoleCreate,
                GuildRoleUpdate,
                GuildRoleDelete,
                ChannelCreate,
                ChannelUpdate,
                ChannelDelete,
                GuildMemberAdd,
                GuildMemberUpdate,
                GuildKeyRoleUpdate,
                GuildMemberNickUpdate,
                GuildMemberAvatarUpdate,
                GuildMemberTimeout,
                GuildMemberRemove,
                GuildMemberKick,
                GuildBanAdd,
                GuildBanRemove,
                InviteCreate,
                InviteDelete,
                MessageUpdate,
                MessageDelete,
                MessageDeleteBulk,
                .. Redirects.Values,
            ];

        public ulong[] AllChannels => _allUnfilteredChannels.Where(c => c != 0).ToArray();
    }
}
