/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   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/>.
 */

package de.steamwar.velocitycore.discord.channels;

import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.discord.DiscordBot;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class CouncilChannel extends StaticMessageChannel {

    private static final Set<CouncilChannel> channels = new HashSet<>();

    private static final Set<Role> roleSet = DiscordBot.getInstance()
            .getConfig()
            .getCouncilThread()
            .keySet()
            .stream()
            .map(roleId -> DiscordBot.getGuild().getRoleById(roleId))
            .collect(Collectors.toSet());

    private static final Map<Role, List<Member>> membersByRole = new HashMap<>();

    private static void initRolesAndMembers(Runnable loaded) {
        List<Long> discordIds = SteamwarUser.getUsersWithDiscordId().stream()
                .map(SteamwarUser::getDiscordId)
                .collect(Collectors.toList());

        membersByRole.clear();
        AtomicInteger countdown = new AtomicInteger(0);
        for (int i = 0; i < discordIds.size(); i += 100) {
            countdown.incrementAndGet();

            List<Long> retrieveIds = discordIds.subList(i, Math.min(discordIds.size(), i + 100));

            DiscordBot.getGuild().retrieveMembersByIds(retrieveIds)
                    .onSuccess(members -> {
                        members.forEach(member -> {
                            for (Role role : roleSet) {
                                if (member.getUnsortedRoles().contains(role)) {
                                    membersByRole.computeIfAbsent(role, __ -> new ArrayList<>()).add(member);
                                }
                            }
                        });

                        if (countdown.decrementAndGet() == 0) {
                            loaded.run();
                        }
                    });
        }
    }

    public static void initCouncilChannels() {
        initRolesAndMembers(() -> {
            DiscordBot.getInstance()
                    .getConfig()
                    .getCouncilThread()
                    .forEach((roleId, threadId) -> {
                        new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId));
                    });
        });
    }

    public static void updateAll() {
        initRolesAndMembers(() -> {
            channels.forEach(StaticMessageChannel::update);
        });
    }

    public CouncilChannel(Role role, ThreadChannel threadChannel) {
        super(threadChannel, () -> {
            MessageCreateBuilder messageCreateBuilder = new MessageCreateBuilder();
            messageCreateBuilder.setContent("# Ratsmitglieder");
            Set<String> uniqueNames = new HashSet<>();
            membersByRole.get(role)
                    .stream()
                    .map(member -> {
                        SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong());
                        String name = steamwarUser == null ? member.getEffectiveName() : steamwarUser.getUserName();
                        UUID uuid = steamwarUser == null ? null : steamwarUser.getUUID();
                        return Map.entry(name, uuid);
                    })
                    .sorted(Map.Entry.comparingByKey())
                    .forEach(entry -> {
                        if (!uniqueNames.add(entry.getKey())) return;
                        messageCreateBuilder.addEmbeds(new EmbedBuilder()
                                .setTitle(entry.getKey())
                                .setImage(entry.getValue() == null ? null : "https://api.steamwar.de/data/skin/" + entry.getValue())
                                .build());
                    });
            return messageCreateBuilder;
        }, event -> {
        });

        channels.add(this);
    }
}
