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

import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.bausystem.features.tracer.TraceRecorder;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import org.bukkit.Bukkit;
import org.bukkit.util.Vector;

import java.util.List;
import java.util.Objects;

public class StabDirection extends StabStep {

    public StabDirection(StabData data) {
        super(data);
    }

    @Override
    protected void start() {
        try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
            e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(data.region.getTestblockArea().getMinPoint(true).toBlockVector3(), data.region.getTestblockArea().getMaxPoint(true).toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
        }

        Trace trace = TraceRecorder.instance.startRecording(data.region);
        runSimulator(() -> {
            TraceRecorder.instance.stopRecording(data.region);
            calculateDirection(trace);
        });
    }

    private void calculateDirection(Trace trace) {
        long tickSinceStart = -1;
        List<TNTPoint> points = null;
        for (List<TNTPoint> current : trace.getHistories()) {
            long ticks = current.get(0).getTicksSinceStart();
            if (points == null || ticks > tickSinceStart) {
                tickSinceStart = ticks;
                points = current;
            } else if (ticks == tickSinceStart && points.get(0).getTntId() < current.get(0).getTntId()) {
                points = current;
            }
        }
        TraceManager.instance.remove(trace);
        if (points == null) {
            stop();
            return;
        }

        TNTPoint current = points.getLast();
        Vector velocity = current.getVelocity();
        if (velocity.getX() < 0) velocity.setX(-velocity.getX());
        if (velocity.getY() < 0) velocity.setY(-velocity.getY());
        if (velocity.getZ() < 0) velocity.setZ(-velocity.getZ());
        if (velocity.getX() > velocity.getY() && velocity.getX() > velocity.getZ()) {
            data.direction = Direction.X;
        } else if (velocity.getY() > velocity.getX() && velocity.getY() > velocity.getZ()) {
            data.direction = Direction.Y;
        } else if (velocity.getZ() > velocity.getX() && velocity.getZ() > velocity.getY()) {
            data.direction = Direction.Z;
        } else {
            stop();
            return;
        }

        Bukkit.getLogger().log(StabData.LEVEL, "Direction: {0}", data.direction);
        data.phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT);
        data.phases.getFirst().setCount(StabData.TNT_INCREASE);
        new StabGenerator(data);
    }

    @Override
    protected void bossbar(BauSystemBossbar bossbar, boolean finished) {
        bossbar.setProgress(0);
        bossbar.setTitle("§eCalculating Stab Direction");
    }
}
