/*
 *   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.discord.listeners;

import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import dev.dewy.nbt.Nbt;
import dev.dewy.nbt.tags.collection.CompoundTag;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.zip.GZIPInputStream;

public class DiscordSchemUpload extends ListenerAdapter {

    private static final Nbt NBT = new Nbt();

    private static final List<String> SCHEM_FILE_ENDINGS = Arrays.asList(".schem", ".schematic");

    @Override
    public void onMessageReceived(MessageReceivedEvent event) {
        if (event.isFromGuild()) return;

        Message message = event.getMessage();
        if(message.getAttachments().isEmpty())
            return;

        DiscordChannel sender = new DiscordChannel(event.getAuthor());
        SteamwarUser user = sender.user();
        if(user.getId() == 0) {
            sender.system("DC_UNLINKED");
            return;
        }

        if(user.isPunished(Punishment.PunishmentType.NoSchemReceiving)) {
            sender.system("DC_SCHEMUPLOAD_NOPERM");
            return;
        }

        for (Message.Attachment attachment : message.getAttachments()) {
            String fileName = attachment.getFileName();
            int dot = fileName.lastIndexOf('.');
            if(dot == -1 || !SCHEM_FILE_ENDINGS.contains(fileName.substring(dot).toLowerCase())) {
                sender.system("DC_SCHEMUPLOAD_IGNORED", attachment.getFileName());
                continue;
            }

            String name = fileName.substring(0, dot);
            if(SchematicNode.invalidSchemName(new String[] {name})) {
                sender.system("DC_SCHEMUPLOAD_INVCHAR", name);
                continue;
            }

            SchematicNode node = SchematicNode.getSchematicNode(user.getId(), name, (Integer) null);
            if(node == null)
                node = SchematicNode.createSchematic(user.getId(), name, null);

            try (InputStream in = attachment.getProxy().download().get()) {
                byte[] bytes = in.readAllBytes();
                CompoundTag tags = NBT.fromStream(new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(bytes))));

                NodeData.SchematicFormat version = NodeData.SchematicFormat.SPONGE_V2;

                if (tags.size() == 1) {
                    version = NodeData.SchematicFormat.SPONGE_V3;
                } else if (tags.contains("Materials")) {
                    version = NodeData.SchematicFormat.MCEDIT;
                }

                NodeData.get(node).saveFromStream(new ByteArrayInputStream(bytes), version);
                sender.system("DC_SCHEMUPLOAD_SUCCESS", name);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException | IOException e) {
                VelocityCore.getLogger().log(Level.SEVERE, "Could not upload schem \"%s\" for user \"%s\"".formatted(name, user.getUserName()), e);
                sender.system("DC_SCHEMUPLOAD_ERROR", name);
            }
        }
    }
}
