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

import com.lunarclient.apollo.ApolloManager;
import com.lunarclient.apollo.libs.protobuf.Any;
import com.lunarclient.apollo.libs.protobuf.InvalidProtocolBufferException;
import com.lunarclient.apollo.libs.protobuf.Message;
import com.lunarclient.apollo.mods.impl.*;
import com.lunarclient.apollo.module.ApolloModuleManager;
import com.lunarclient.apollo.module.ApolloModuleManagerImpl;
import com.lunarclient.apollo.module.modsetting.ModSettingModule;
import com.lunarclient.apollo.network.NetworkOptions;
import com.lunarclient.apollo.option.Options;
import com.lunarclient.apollo.player.AbstractApolloPlayer;
import com.lunarclient.apollo.player.v1.ModMessage;
import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.sql.Mod;
import lombok.AllArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.logging.Level;

public class Lunar {
    // https://lunarclient.dev/apollo/introduction
    // https://github.com/LunarClient/Apollo

    private final ApolloModuleManager manager = new ApolloModuleManagerImpl().addModule(ModSettingModule.class);

    public Lunar() { //TODO seems defunct
        Options modSettings = manager.getModule(ModSettingModule.class).getOptions();
        modSettings.set(ModReplaymod.ENABLED, false); // TODO check if restrictions working
        modSettings.set(ModFreelook.ENABLED, false);
        modSettings.set(ModHypixelMod.ENABLED, false);
        modSettings.set(ModMinimap.ENABLED, false);
        modSettings.set(ModNametag.ENABLED, false);
        modSettings.set(ModTeamView.ENABLED, false);
        modSettings.set(ModTntCountdown.ENABLED, false);
        modSettings.set(ModToggleSneak.TOGGLE_SNEAK_CONTAINER, false);
    }

    public void sendRestrictions(Player player) {
        NetworkOptions.sendOptions(manager.getModules(), true, new SWApolloPlayer(player));
    }

    public void handlePluginMessage(PluginMessageEvent event) {
        Player player = (Player) event.getSource();
        Any packet;

        try {
            packet = Any.parseFrom(event.getData());
        } catch (InvalidProtocolBufferException e) {
            throw new SecurityException(e);
        }

        handle(PlayerHandshakeMessage.class, packet, handshake -> {
            List<Mod> mods = new ArrayList<>();

            for(ModMessage mod : handshake.getInstalledModsList()) {
                switch(mod.getType()) {
                    case TYPE_FABRIC_INTERNAL, TYPE_FORGE_INTERNAL:
                        // Controlled with ModSettings
                        break;
                    case TYPE_FABRIC_EXTERNAL:
                        mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FABRIC));
                        break;
                    case TYPE_FORGE_EXTERNAL:
                        mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FORGE));
                        break;
                    default:
                        VelocityCore.getLogger().log(Level.INFO, () -> player.getUsername() + " uses Lunar mod with unknown type " + mod);
                        break;
                }
            }

            ModUtils.handleMods(player, mods);
        });
    }

    private <T extends Message> void handle(Class<T> type, Any packet, Consumer<T> handler) {
        try {
            handler.accept(packet.unpack(type));
        } catch (InvalidProtocolBufferException ignored) { /*ignored*/ }
    }

    @AllArgsConstructor
    private static class SWApolloPlayer extends AbstractApolloPlayer {

        private final Player player;

        @Override
        public void sendPacket(Message message) {
            sendPacket(Any.pack(message).toByteArray());
        }

        @Override
        public void sendPacket(byte[] bytes) {
            player.sendPluginMessage(MinecraftChannelIdentifier.from(ApolloManager.PLUGIN_MESSAGE_CHANNEL), bytes);
        }

        @Override public UUID getUniqueId() { return player.getUniqueId(); }
        @Override public String getName() { return player.getUsername(); }
        @Override public boolean hasPermission(String s) { return player.hasPermission(s); }
        @Override public Object getPlayer() { return player; }
    }
}
