/*
 *   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.schematicsystem.commands.schematiccommand.parts;

import com.sk89q.worldedit.extent.clipboard.Clipboard;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.schematicsystem.SafeSchematicNode;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.schematicsystem.autocheck.AutoChecker;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
import de.steamwar.sql.*;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;

import java.io.IOException;

import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;

@AbstractSWCommand.PartOf(SchematicCommand.class)
@Linked
public class ModifyPart extends SWCommand {
    public ModifyPart() {
        super(null);
    }

    @Register("changetype")
    @Register("submit")
    public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
        TextComponent base = new TextComponent();

        Clipboard clipboard;
        try {
            clipboard = new SchematicData(node).load();
        } catch (IOException ignored) {
            SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
            return;
        }

        String breadcrumb = node.generateBreadcrumbs(SteamwarUser.get(player.getUniqueId()));

        SchematicType.values().parallelStream()
                .filter(SchematicType::isAssignable)
                .filter(type -> SchematicSystem.getGameModeConfig(type) == null || AutoChecker.impl.sizeCheck(clipboard, SchematicSystem.getGameModeConfig(type)).fastOk())
                .forEach(type -> {
                    TextComponent component = new TextComponent(type.name() + " ");
                    component.setColor(ChatColor.GRAY);
                    component.setBold(true);
                    component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(SchematicSystem.MESSAGE.parse("COMMAND_CHANGE_TYPE_SELECT", player))));
                    component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem changetype " + breadcrumb + " " + type.name()));
                    base.addExtra(component);
                });

        player.spigot().sendMessage(base);
    }

    @Register("changetype")
    @Register("submit")
    public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type) {
        changeType(player, node, type, null);
    }

    @Register("changetype")
    @Register("submit")
    public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type, SchematicCommand.Extend extend) {
        SchematicCommandUtils.changeType(player, node, type, extend);
    }

    @Register("move")
    public void moveToNull(Player player, @ErrorMessage("COMMAND_INVALID_NODE") SchematicNode node) {
        move(player, node, "/");
    }

    @Register("move")
    public void move(Player player, @ErrorMessage("COMMAND_INVALID_NODE") SchematicNode node, @Mapper("dirStringMapper") String name) {
        SteamwarUser user = getUser(player);

        if (name.equals("/")) {
            if (node.getOwner() == user.getId()) {
                node.setParent(null);
            } else if (NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
                NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
                member.setParentId(null);
            } else {
                SchematicSystem.MESSAGE.send("COMMAND_NOT_OWN", player);
                return;
            }
        } else {
            if (name.startsWith("/")) name = name.substring(1);
            if (name.endsWith("/")) name = name.substring(0, name.length() - 1);
            String[] layers = name.split("/");
            if (invalidSchemName(player, layers)) return;
            SchematicNode newNode = mkdirs(layers, user, 0);
            if (SchematicNode.parentsOfNode(user, newNode.getId()).stream().anyMatch(n -> n.getId() == node.getId())) {
                SchematicSystem.MESSAGE.send("COMMAND_MOVE_RECURSIVE", player);
                return;
            }

            if (node.getOwner() == user.getId()) {
                SafeSchematicNode.Result result = SafeSchematicNode.setParent(user, node, newNode);
                if (!result.isSuccessful()) {
                    result.sendError(player);
                    return;
                }
            } else if (NodeMember.getNodeMember(node.getId(), user.getId()) != null) {
                NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
                member.setParentId(newNode.getId());
            } else {
                SchematicSystem.MESSAGE.send("COMMAND_NOT_OWN", player);
                return;
            }
        }
        SchematicSystem.MESSAGE.send("COMMAND_MOVE_DONE", player, SchematicNode.byIdAndUser(user, node.getId()).generateBreadcrumbs(user));
    }

    @Register("rename")
    public void rename(Player player, @Validator("isOwnerValidator") SchematicNode node, String name) {
        SteamwarUser user = getUser(player);
        if (invalidSchemName(player, new String[]{name})) {
            return;
        }
        SafeSchematicNode.Result result = SafeSchematicNode.setName(user, node, name);
        if (!result.isSuccessful()) {
            result.sendError(player);
            return;
        }
        SchematicSystem.MESSAGE.send("COMMAND_RENAME_DONE", player, node.generateBreadcrumbs(user));
    }

    @Register("delete")
    public void deleteSchem(Player player, SchematicNode node) {
        SteamwarUser user = SteamwarUser.get(player.getUniqueId());
        if (node.getOwner() != user.getId()) {
            NodeMember member = NodeMember.getNodeMember(node.getId(), user.getId());
            if (member == null) {
                SchematicSystem.MESSAGE.send("COMMAND_DELETE_NOT_OWN", player);
                return;
            }
            member.delete();
            SchematicSystem.MESSAGE.send("COMMAND_DELETE_MEMBER", player);
            return;
        }

        if (node.isDir()) {
            if (SchematicNode.getSchematicNodeInNode(node).isEmpty()) {
                SchematicSystem.MESSAGE.send("COMMAND_DELETE_DIR", player, node.generateBreadcrumbs(user));
                node.delete();
            } else {
                SchematicSystem.MESSAGE.send("COMMAND_DELETE_DIR_FULL", player);
            }
        } else {
            SchematicSystem.MESSAGE.send("COMMAND_DELETE_SCHEM", player, node.generateBreadcrumbs(user));
            node.delete();
        }
    }

    @Register("replacecolor")
    public void replacecolor(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
        boolean state = !node.replaceColor();
        node.setReplaceColor(state);
        SchematicSystem.MESSAGE.send(state ? "COMMAND_REPLACE_COLOR_ON" : "COMMAND_REPLACE_COLOR_OFF", player, node.getName());
    }
}
