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

import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
import de.steamwar.inventory.InvCallback;
import de.steamwar.inventory.SWItem;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import yapion.hierarchy.types.YAPIONObject;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiConsumer;

@Getter
@Setter
public abstract class SimulatorElement<T extends SimulatorPhase> {
    protected Material material;
    protected final Vector position;
    protected boolean disabled = false;
    protected final List<T> phases = new ArrayList<>();

    protected SimulatorElement(Material material, Vector position) {
        this.material = material;
        this.position = position;
    }

    public SimulatorElement<T> add(T setting) {
        phases.add(setting);
        return this;
    }

    public void sort() {
        phases.sort(Comparator.comparingInt(SimulatorPhase::getTickOffset));
    }

    public abstract String getName(Player player);

    public int getBaseTick() {
        return phases.stream()
                .mapToInt(value -> value.tickOffset)
                .min()
                .orElse(0);
    }

    public void changeBaseTicks(int tick) {
        phases.forEach(t -> {
            t.tickOffset += tick;
        });
    }

    public void move(double x, double y, double z) {
        position.setX(position.getX() + x);
        position.setY(position.getY() + y);
        position.setZ(position.getZ() + z);
    }

    public abstract Material getWorldMaterial();

    public abstract Material getWorldDisabledMaterial();

    public abstract boolean canBeInGroup(SimulatorGroup simulatorGroup);

    public Vector getWorldPos() {
        return position;
    }

    public SWItem toItem(Player player, InvCallback invCallback) {
        List<String> lore = new ArrayList<>();
        lore.add("§7Phase count§8:§e " + phases.size());
        lore.add("§7Tick§8:§e " + getBaseTick());
        lore.add("");
        lore.add("§7X§8:§e " + position.getX());
        lore.add("§7Y§8:§e " + position.getY());
        lore.add("§7Z§8:§e " + position.getZ());
        if (disabled) {
            lore.add("");
            lore.add("§cDisabled");
        }
        return new SWItem(material, "§e" + getName(player), lore, disabled, invCallback);
    }

    public void toSimulatorActions(BiConsumer<Integer, SimulatorAction> tickStart, BiConsumer<Integer, SimulatorAction> tickEnd) {
        if (disabled) return;
        phases.forEach(phase -> {
            phase.toSimulatorActions(position.clone(), tickStart, tickEnd);
        });
    }

    public abstract void open(Player player, Simulator simulator, SimulatorGroup group, SimulatorBaseGui back);

    public SimulatorGroup getGroup(Simulator simulator) {
        return simulator.getGroups().stream()
                .filter(simulatorGroup -> simulatorGroup.getElements().contains(this))
                .findFirst()
                .orElse(null);
    }

    public abstract String getType();
    public void saveExtra(YAPIONObject elementObject) {}
    public void loadExtra(YAPIONObject elementObject) {}
}
