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

import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {

    private final SimulatorGroup parent;
    private final ObserverElement observer;
    private final SimulatorBaseGui back;

    public SimulatorObserverGui(Player player, Simulator simulator, SimulatorGroup parent, ObserverElement observer, SimulatorBaseGui back) {
        super(player, simulator, 6 * 9, observer.getPhases());
        this.parent = parent;
        this.observer = observer;
        this.back = back;
    }

    @Override
    public String baseTitle() {
        return "Observer";
    }

    @Override
    public void headerAndFooter() {
        if (observer.getPhases().isEmpty()) {
            back.open();
            SimulatorWatcher.update(simulator);
            return;
        }

        observer.sort();

        // Back Arrow
        inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> {
            if (parent.getElements().contains(observer)) {
                back.open();
            } else {
                SimulatorGroup newParent = observer.getGroup(simulator);
                if (newParent == null) {
                    player.closeInventory();
                    return;
                }
                SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
                if (newParent.getElements().size() == 1) {
                    simulatorGui.open();
                } else {
                    new SimulatorGroupGui(player, simulator, newParent, simulatorGui).open();
                }
            }
        }).setCustomModelData(CMDs.BACK));

        inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
            observer.getPhases().clear();
            SimulatorWatcher.update(simulator);
        }).setCustomModelData(CMDs.Simulator.DELETE));

        // Material Chooser
        inventory.setItem(4, observer.toItem(player, clickType -> {
            new SimulatorMaterialGui(player, simulator, observer::getMaterial, observer::setMaterial, this).open();
        }));

        // Settings
        inventory.setItem(47, new SWItem(Material.REPEATER, "§eSettings", clickType -> {
            new SimulatorObserverSettingsGui(player, simulator, observer, this).open();
        }).setCustomModelData(CMDs.Simulator.SETTINGS));

        // Enable/Disable
        inventory.setItem(48, new SWItem(observer.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, observer.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
            observer.setDisabled(!observer.isDisabled());
            SimulatorWatcher.update(simulator);
        }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));

        // Group chooser
        inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> {
            new SimulatorGroupChooserGui(player, simulator, observer, observer.getGroup(simulator), this).open();
        }).setCustomModelData(CMDs.Simulator.JOIN_GROUP));
    }

    @Override
    public SWItem[] column(ObserverPhase observerPhase, int index) {
        int min;
        if (index > 0) {
            min = data.get(index - 1).getTickOffset() + 4;
        } else {
            min = 0;
        }

        int max;
        if (index < data.size() - 1) {
            max = data.get(index + 1).getTickOffset() - 4;
        } else {
            max = Integer.MAX_VALUE - 4;
        }

        List<String> lore = new ArrayList<>();
        lore.add("§7Time§8:§e " + observerPhase.getTickOffset());
        lore.add("§7Order§8:§e " + observerPhase.getOrder());
        lore.add("");
        lore.add("§7Orientation§8:§e " + observerPhase.getOrientation().name());
        lore.add("");
        lore.add("§7Click§8:§e Edit");
        lore.add("§7Middle-Click§8:§e Remove");
        SWItem observer = new SWItem(Material.OBSERVER, "§eObserver", lore, false, clickType -> {
            if (clickType == ClickType.MIDDLE) {
                this.observer.getPhases().remove(observerPhase);
                SimulatorWatcher.update(simulator);
            } else {
                new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
            }
        });
        observer.getItemStack().setAmount(Math.min(Math.max(observerPhase.getTickOffset(), 1), 64));

        Supplier<Integer> getter = observerPhase::getTickOffset;
        Consumer<Integer> setter = observerPhase::setTickOffset;
        return new SWItem[]{
                new SWItem(getter.get() < max ? Material.LIME_DYE : Material.GRAY_DYE, "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
                    if (clickType == ClickType.DOUBLE_CLICK) return;
                    setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
                    SimulatorWatcher.update(simulator);
                }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
                observer,
                new SWItem(getter.get() > min ? Material.RED_DYE : Material.GRAY_DYE, "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
                    if (clickType == ClickType.DOUBLE_CLICK) return;
                    setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
                    SimulatorWatcher.update(simulator);
                }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
                new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
                    new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
                }).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION),
        };
    }

    @Override
    public SWItem[] lastColumn() {
        return new SWItem[]{
                new SWItem(Material.LIME_DYE, "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
                    addNewPhase(clickType.isShiftClick());
                }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
                new SWItem(Material.QUARTZ, "§eObserver§8:§a New Phase", clickType -> {
                    addNewPhase(false);
                }).setCustomModelData(CMDs.Simulator.NEW_PHASE),
                new SWItem(Material.GRAY_DYE, "§7", clickType -> {
                }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
        };
    }

    private void addNewPhase(boolean shift) {
        ObserverPhase lastElement = observer.getPhases().get(observer.getPhases().size() - 1);
        ObserverPhase newPhase = new ObserverPhase(lastElement.getTickOffset() + 4);
        if (shift) newPhase.setTickOffset(newPhase.getTickOffset() + 5);
        scroll += 2;
        observer.add(newPhase);
        SimulatorWatcher.update(simulator);
    }
}
