/*
 *   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.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.linkage.Linked;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.ZeroArgFunction;

@Linked
public class TracerLib implements LuaLib {
    @Override
    public String name() {
        return "tracer";
    }

    private static LuaTable convertTrace(Trace trace) {
        LuaTable luaTrace = new LuaTable();

        luaTrace.set("getRecords", new ZeroArgFunction() {
            @Override
            public LuaValue call() {
                return LuaValue.listOf(
                        trace.getHistories()
                                .stream()
                                .map((history) -> LuaValue.listOf(history
                                        .stream()
                                        .map(TracerLib::convertTntPoint)
                                        .toArray(LuaValue[]::new)))
                                .toArray(LuaValue[]::new));
            }
        });

        luaTrace.set("getId", new ZeroArgFunction() {
            @Override
            public LuaValue call() {
                return LuaValue.valueOf(trace.getUuid().toString());
            }
        });


        return luaTrace;
    }

    private static LuaTable convertTntPoint(TNTPoint tntPoint) {
        Location pointPos = tntPoint.getLocation();
        LuaTable luaPos = LuaValue.tableOf(new LuaValue[]{
                LuaValue.valueOf("x"), LuaValue.valueOf(pointPos.getX()),
                LuaValue.valueOf("y"), LuaValue.valueOf(pointPos.getY()),
                LuaValue.valueOf("z"), LuaValue.valueOf(pointPos.getZ()),
        });

        Vector pointVel = tntPoint.getVelocity();
        LuaTable luaVel = LuaValue.tableOf(new LuaValue[]{
                LuaValue.valueOf("x"), LuaValue.valueOf(pointVel.getX()),
                LuaValue.valueOf("y"), LuaValue.valueOf(pointVel.getY()),
                LuaValue.valueOf("z"), LuaValue.valueOf(pointVel.getZ()),
        });

        return LuaValue.tableOf(new LuaValue[]{
                LuaValue.valueOf("pos"), luaPos,
                LuaValue.valueOf("vel"), luaVel,
                LuaValue.valueOf("ticksSinceStart"), LuaValue.valueOf(tntPoint.getTicksSinceStart()),
                LuaValue.valueOf("fuse"), LuaValue.valueOf(tntPoint.getFuse()),
                LuaValue.valueOf("isExplosion"), LuaValue.valueOf(tntPoint.isExplosion()),
                LuaValue.valueOf("isInWater"), LuaValue.valueOf(tntPoint.isInWater()),
                LuaValue.valueOf("hasDestroyedBuild"), LuaValue.valueOf(tntPoint.isDestroyedBuildArea()),
                LuaValue.valueOf("hasDestroyedTestblock"), LuaValue.valueOf(tntPoint.isDestroyedTestBlock())
        });
    }

    @Override
    public LuaTable get(Player player) {
        LuaTable rootTable = LuaValue.tableOf();

        rootTable.set("getTraces", new ZeroArgFunction() {
                    @Override
                    public LuaValue call() {
                        return LuaValue.listOf(TraceManager.instance.getAll()
                                .stream()
                                .map(TracerLib::convertTrace)
                                .toArray(LuaValue[]::new));
                    }
                }

        );

        return rootTable;
    }
}
