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

import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.World;
import de.steamwar.bausystem.world.regions.PasteOptions;
import de.steamwar.bausystem.world.regions.Point;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;

public class WorldeditWrapper12 implements WorldeditWrapper.IWorldeditWrapper {

    private final WorldEditPlugin WORLDEDIT_PLUGIN = ((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"));
    private final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0));

    @Override
    public void setSelection(Player p, Point minPoint, Point maxPoint) {
        WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, toVector(minPoint), toVector(maxPoint)));
    }

    @Override
    public EditSession paste(File file, int x, int y, int z, PasteOptions pasteOptions) {
        World w = new BukkitWorld(Bukkit.getWorlds().get(0));
        Clipboard clipboard;
        try {
            clipboard = Objects.requireNonNull(ClipboardFormat.findByFile(file)).getReader(new FileInputStream(file)).read(w.getWorldData());
        } catch (NullPointerException | IOException e) {
            throw new SecurityException("Bausystem schematic not found", e);
        }

        return paste(clipboard, x, y, z, pasteOptions);
    }

    @Override
    public EditSession paste(Clipboard clipboard, int x, int y, int z, PasteOptions pasteOptions) {
        World w = new BukkitWorld(Bukkit.getWorlds().get(0));

        Vector dimensions = clipboard.getDimensions();
        Vector v = new Vector(x, y, z);
        Vector offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
        AffineTransform aT = new AffineTransform();
        if (pasteOptions.isRotate()) {
            aT = aT.rotateY(180);
            v = v.add(dimensions.getX() / 2 + dimensions.getX() % 2, 0, dimensions.getZ() / 2 + dimensions.getZ() % 2).subtract(offset.multiply(-1, 1, -1)).subtract(1, 0, 1);
        } else {
            v = v.subtract(dimensions.getX() / 2 - dimensions.getX() % 2, 0, dimensions.getZ() / 2 - dimensions.getZ() % 2).subtract(offset);
        }

        EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(w, -1);
        ClipboardHolder ch = new ClipboardHolder(clipboard, w.getWorldData());
        ch.setTransform(aT);

        if (pasteOptions.isReset()) {
            try {
                e.setBlocks(new CuboidRegion(toVector(pasteOptions.getMinPoint()), toVector(pasteOptions.getMaxPoint())), new BaseBlock(BlockID.AIR));
            } catch (MaxChangedBlocksException ex) {
                throw new SecurityException("Max blocks changed?", ex);
            }
        }
        Operations.completeBlindly(ch.createPaste(e, w.getWorldData()).to(v).ignoreAirBlocks(pasteOptions.isIgnoreAir()).build());
        return e;
    }

    @Override
    public boolean isWorldEditCommand(String command) {
        if (command.startsWith("/")) {
            command = command.replaceFirst("/", "");
        }
        command = command.toLowerCase();
        return ((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit")).getWorldEdit().getPlatformManager()
                .getCommandManager().getDispatcher().get(command) != null;
    }

    private Vector toVector(Point point) {
        return Vector.toBlockPoint(point.getX(), point.getY(), point.getZ());
    }
}
