/*
 *   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.script.lua.libs;

import de.steamwar.bausystem.features.loader.Loader;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.RegionSystem;
import de.steamwar.bausystem.region.flags.*;
import de.steamwar.linkage.Linked;
import org.bukkit.entity.Player;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;

import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;

@Linked
public class RegionLib implements LuaLib {

    @Override
    public String name() {
        return "region";
    }

    private LuaTable create(Supplier<Region> region, Player player) {
        LuaTable table = LuaValue.tableOf();

        table.set("name", getter(() -> region.get().getID().toString()));
        table.set("id", getter(() -> region.get().getID().toString()));
        table.set("type", getter(() -> {
            Region rg = region.get();
            if (rg.getType().isGlobal()) {
                return "global";
            }
            List<String> chatNames = rg.getGameModeConfig().Server.ChatNames;
            if (chatNames.isEmpty()) {
                return "unknown";
            }
            return chatNames.get(0).toLowerCase();
        }));

        LuaValue tntLib = LuaValue.tableOf();
        tntLib.set("mode", getter(() -> region.get().getRegionData().get(Flag.TNT).nameWithDefault()));
        tntLib.set("enabled", getter(() -> region.get().getRegionData().get(Flag.TNT).orElse(null) != TNTMode.DENY));
        tntLib.set("onlyTb", getter(() -> region.get().getRegionData().get(Flag.TNT).orElse(null) == TNTMode.ONLY_TB));
        table.set("tnt", tntLib);

        table.set("fire", getter(() -> region.get().getRegionData().get(Flag.FIRE).orElse(null) == FireMode.ALLOW));
        table.set("freeze", getter(() -> region.get().getRegionData().get(Flag.FREEZE).orElse(null) == FreezeMode.ACTIVE));
        table.set("protect", getter(() -> region.get().getRegionData().get(Flag.PROTECT).orElse(null) == ProtectMode.ACTIVE));

        //LuaValue traceLib = LuaValue.tableOf();
        //traceLib.set("active", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof ActiveTracer));
        //traceLib.set("auto", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof AutoTraceRecorder));
        //traceLib.set("status", getter(() -> Recorder.INSTANCE.get(region.get()).scriptState()));
        //traceLib.set("time", getter(() -> Recorder.INSTANCE.get(region.get()).scriptTime()));

        //table.set("trace", traceLib);

        Loader loader = Loader.getLoader(player);
        table.set("loader", getter(() -> loader == null ? "OFF" : loader.getStage().name()));

        table.set("copyPoint", getter(() -> toPos(region.get().getBuildArea().getCopyPoint())));
        table.set("minPointBuild", getter(() -> toPos(region.get().getBuildArea().getMinPoint(false))));
        table.set("maxPointBuild", getter(() -> toPos(region.get().getBuildArea().getMinPoint(false))));
        table.set("minPointBuildExtension", getter(() -> toPos(region.get().getBuildArea().getMinPoint(true))));
        table.set("maxPointBuildExtension", getter(() -> toPos(region.get().getBuildArea().getMinPoint(true))));
        table.set("testblockPoint", getter(() -> toPos(region.get().getTestblockArea().getCopyPoint())));
        table.set("minPointTestblock", getter(() -> toPos(region.get().getTestblockArea().getMinPoint(false))));
        table.set("maxPointTestblock", getter(() -> toPos(region.get().getTestblockArea().getMinPoint(false))));
        table.set("minPointTestblockExtension", getter(() -> toPos(region.get().getTestblockArea().getMinPoint(true))));
        table.set("maxPointTestblockExtension", getter(() -> toPos(region.get().getTestblockArea().getMinPoint(true))));

        return table;
    }

    @Override
    public LuaTable get(Player player) {
        LuaTable table = create(() -> Region.getRegion(player.getLocation()), player);
        table.set("get", new OneArgFunction() {
            @Override
            public LuaValue call(LuaValue arg) {
                return create(() -> RegionSystem.INSTANCE.getRegion(UUID.fromString(arg.checkjstring())).orElse(RegionSystem.INSTANCE.getGlobalRegion()), player);
            }
        });

        table.set("list", getter(() -> LuaValue.listOf(RegionSystem.INSTANCE.getRegions().map(region -> create(() -> region, player)).toArray(LuaTable[]::new))));

        return table;
    }
}
