/*
 *   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.features.worldedit.utils;

import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.SignBlock;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import org.bukkit.Bukkit;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.Random;
import java.util.function.BiConsumer;

public class SpecialReplace implements Mask, Pattern {

    private EditSession editSession;
    private Map<String, String> replacements;
    private Random random = new Random();
    private int percentage;
    private BiConsumer<BlockData, BlockData> blockDataMerger;

    public SpecialReplace(EditSession editSession, Map<String, String> replacements, int percentage) {
        this(editSession, replacements, percentage, (_1, _2) -> {
        });
    }

    public SpecialReplace(EditSession editSession, Map<String, String> replacements, int percentage, BiConsumer<BlockData, BlockData> blockDataMerger) {
        this.editSession = editSession;
        this.replacements = replacements;
        this.percentage = percentage;
        this.blockDataMerger = blockDataMerger;
    }

    @Override
    public boolean test(BlockVector3 blockVector3) {
        if (random.nextInt(100) > percentage) return false;
        return replacements.containsKey(editSession.getFullBlock(blockVector3).getBlockType().getId());
    }

    @Nullable
    @Override
    public Mask2D toMask2D() {
        return null;
    }

    @Override
    public BaseBlock applyBlock(BlockVector3 position) {
        BaseBlock block = editSession.getFullBlock(position);
        String[] signText = null;
        if (block.getBlockType().getId().endsWith("sign")) {
            Sign sign = (Sign) BukkitAdapter.adapt(editSession.getWorld()).getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()).getState();
            signText = sign.getLines();
        }
        BlockData blockData = BukkitAdapter.adapt(block);
        String s = blockData.getAsString();
        String rest = "";
        if (s.contains("[")) {
            int i = s.indexOf("[");
            rest = s.substring(i);
            s = s.substring(0, i);
        }
        try {
            BaseBlock newBlock = BukkitAdapter.adapt(Bukkit.createBlockData(replacements.getOrDefault(s, s) + rest)).toBaseBlock();
            if (newBlock.getBlockType().getId().endsWith("sign")) {
                newBlock = new SignBlock(newBlock.toImmutableState(), signText).toBaseBlock();
            }
            return newBlock;
        } catch (IllegalArgumentException e) {
            try {
                BlockData newBlockData = Bukkit.createBlockData(replacements.getOrDefault(s, s));
                BlockData oldBlockData = BukkitAdapter.adapt(editSession.getFullBlock(position));
                blockDataMerger.accept(oldBlockData, newBlockData);
                return BukkitAdapter.adapt(newBlockData).toBaseBlock();
            } catch (IllegalArgumentException ex) {
                return editSession.getFullBlock(position);
            }
        }
    }

    @Override
    public Mask copy() {
        return this;
    }
}
