/*
 *   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.redstone.RedstoneElement;
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
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 lombok.AllArgsConstructor;
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 SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGui.RedstoneSubPhase> {

    private final SimulatorGroup parent;
    private final RedstoneElement redstone;
    private final SimulatorBaseGui back;

    public SimulatorRedstoneGui(Player player, Simulator simulator, SimulatorGroup parent, RedstoneElement redstone, SimulatorBaseGui back) {
        super(player, simulator, 6 * 9, new ArrayList<>());
        this.parent = parent;
        this.redstone = redstone;
        this.back = back;
    }

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

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

        data.clear();
        redstone.getPhases().forEach(redstonePhase -> {
            data.add(new RedstoneSubPhase(true, redstonePhase));
            data.add(new RedstoneSubPhase(false, redstonePhase));
        });
        data.sort(null);

        // Back Arrow
        inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> {
            if (parent.getElements().contains(redstone)) {
                back.open();
            } else {
                SimulatorGroup newParent = redstone.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 -> {
            redstone.getPhases().clear();
            SimulatorWatcher.update(simulator);
        }).setCustomModelData(CMDs.Simulator.DELETE));

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

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

        // Enable/Disable
        inventory.setItem(48, new SWItem(redstone.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, redstone.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
            redstone.setDisabled(!redstone.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, redstone, redstone.getGroup(simulator), this).open();
        }).setCustomModelData(CMDs.Simulator.JOIN_GROUP));
    }

    @Override
    public SWItem[] column(RedstoneSubPhase redstoneSubPhase, int index) {
        int min;
        if (index % 2 == 0 && index > 0) {
            RedstoneSubPhase subPhase = data.get(index - 1);
            min = subPhase.phase.getTickOffset() + subPhase.phase.getLifetime() + 1;
        } else {
            min = 0;
        }

        int max;
        if (index % 2 == 0 && index < data.size() - 2) {
            RedstoneSubPhase subPhase = data.get(index + 2);
            max = subPhase.phase.getTickOffset() - redstoneSubPhase.phase.getLifetime() - 1;
        } else if (index % 2 != 0 && index < data.size() - 1) {
            RedstoneSubPhase subPhase = data.get(index + 1);
            max = subPhase.phase.getTickOffset() - redstoneSubPhase.phase.getTickOffset() - 1;
        } else {
            max = Integer.MAX_VALUE - 5;
        }

        List<String> lore = new ArrayList<>();
        int time = redstoneSubPhase.phase.getTickOffset() + (redstoneSubPhase.place ? 0 : redstoneSubPhase.phase.getLifetime());
        if (redstoneSubPhase.place) {
            lore.add("§7Time§8:§e " + time);
            lore.add("§7Order§8:§e " + redstoneSubPhase.phase.getOrder());
        } else {
            lore.add("§7Time§8:§e " + time);
            lore.add("§7Activation Time§8:§e " + redstoneSubPhase.phase.getLifetime());
        }
        lore.add("");
        lore.add("§7Click§8:§e Edit");
        lore.add("§7Middle-Click§8:§e Remove");
        SWItem redstone = new SWItem(redstoneSubPhase.place ? Material.REDSTONE_BLOCK : Material.STONE, redstoneSubPhase.place ? "§eActivate" : "§eDeactivate", lore, false, clickType -> {
            if (clickType == ClickType.MIDDLE) {
                this.redstone.getPhases().remove(redstoneSubPhase.phase);
                SimulatorWatcher.update(simulator);
            } else {
                new SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, this).open();
            }
        });
        redstone.getItemStack().setAmount(Math.max(1, Math.min(time, 64)));

        Supplier<Integer> getter = redstoneSubPhase.place ? redstoneSubPhase.phase::getTickOffset : redstoneSubPhase.phase::getLifetime;
        Consumer<Integer> setter = redstoneSubPhase.place ? redstoneSubPhase.phase::setTickOffset : redstoneSubPhase.phase::setLifetime;
        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),
                redstone,
                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 SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, 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.REDSTONE, "§eRedstone§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) {
        RedstonePhase lastElement = redstone.getPhases().get(redstone.getPhases().size() - 1);
        RedstonePhase newPhase = new RedstonePhase(lastElement.getTickOffset() + lastElement.getLifetime() + 1);
        if (shift) newPhase.setTickOffset(newPhase.getTickOffset() + 5);
        scroll += 2;
        redstone.add(newPhase);
        SimulatorWatcher.update(simulator);
    }

    @AllArgsConstructor
    public static class RedstoneSubPhase implements Comparable<RedstoneSubPhase> {
        private boolean place;
        private RedstonePhase phase;

        @Override
        public int compareTo(RedstoneSubPhase o) {
            int thisTick = phase.getTickOffset() + (place ? 0 : phase.getLifetime());
            int otherTick = o.phase.getTickOffset() + (o.place ? 0 : o.phase.getLifetime());

            int compare = Integer.compare(thisTick, otherTick);
            if (compare != 0) {
                return compare;
            }

            if (place && !o.place) {
                return -1;
            }
            if (!place && o.place) {
                return 1;
            }
            if (!place) {
                return 0;
            }

            return Integer.compare(phase.getOrder(), o.phase.getOrder());
        }
    }
}
