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

import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
import org.bukkit.Material;
import org.bukkit.util.Vector;
import yapion.exceptions.YAPIONException;
import yapion.hierarchy.types.YAPIONArray;
import yapion.hierarchy.types.YAPIONObject;
import yapion.parser.YAPIONParser;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class SimulatorFormatSimulatorLoader implements SimulatorLoader {

    @Override
    public Optional<List<Simulator>> load(File file) {
        if (!file.getName().endsWith(".simulator")) {
            return Optional.empty();
        }

        YAPIONObject yapionObject;
        try {
            yapionObject = YAPIONParser.parse(file);
        } catch (YAPIONException | IOException e) {
            return Optional.empty();
        }

        String name = file.getName().substring(0, file.getName().length() - ".simulator".length());

        Simulator simulator = new Simulator(name);
        simulator.setMaterial(Material.valueOf(yapionObject.getStringOrDefault("material", "BARREL")));

        YAPIONArray tntElements = yapionObject.getArrayOrDefault("tntElements", new YAPIONArray());
        for (YAPIONObject element : tntElements.streamObject().collect(Collectors.toList())) {
            if (element.containsKey("elements")) {
                simulator.add(loadGroup(element));
            } else {
                simulator.add(loadElement(element));
            }
        }

        file.delete();
        return Optional.of(Collections.singletonList(simulator));
    }

    private SimulatorGroup loadGroup(YAPIONObject element) {
        double x = element.getDoubleOrDefault("x", 0);
        double y = element.getDoubleOrDefault("y", 0);
        double z = element.getDoubleOrDefault("z", 0);
        int tickOffset = element.getIntOrDefault("tickOffset", 0);

        SimulatorGroup simulatorGroup = new SimulatorGroup();
        simulatorGroup.setDisabled(element.getBooleanOrDefault("disabled", false));

        YAPIONArray elements = element.getArrayOrDefault("elements", new YAPIONArray());
        for (YAPIONObject e : elements.streamObject().collect(Collectors.toList())) {
            simulatorGroup.add(loadElement(e, x, y, z, tickOffset));
        }

        return simulatorGroup;
    }

    private TNTElement loadElement(YAPIONObject element, double dx, double dy, double dz, int dTickOffset) {
        TNTElement tntElement = new TNTElement(new Vector(element.getDouble("x") + dx, element.getDouble("y") + dy, element.getDouble("z") + dz));
        tntElement.setDisabled(element.getBooleanOrDefault("disabled", false));
        tntElement.setMaterial(Material.valueOf(element.getStringOrDefault("material", "TNT")));

        TNTPhase tntPhase = loadPhase(element);
        tntPhase.setTickOffset(tntPhase.getTickOffset() + dTickOffset);
        tntElement.add(tntPhase);

        return tntElement;
    }

    private SimulatorGroup loadElement(YAPIONObject element) {
        SimulatorGroup simulatorGroup = new SimulatorGroup();

        TNTElement tntElement = new TNTElement(new Vector(element.getDouble("x"), element.getDouble("y"), element.getDouble("z")));
        tntElement.setDisabled(element.getBooleanOrDefault("disabled", false));
        tntElement.setMaterial(Material.valueOf(element.getStringOrDefault("material", "TNT")));
        simulatorGroup.add(tntElement);

        tntElement.add(loadPhase(element));

        return simulatorGroup;
    }

    private TNTPhase loadPhase(YAPIONObject element) {
        TNTPhase tntPhase = new TNTPhase();
        tntPhase.setLifetime(element.getIntOrDefault("fuseTicks", 80));
        tntPhase.setCount(element.getIntOrDefault("count", 1));
        tntPhase.setTickOffset(element.getIntOrDefault("tickOffset", 0));
        tntPhase.setXJump(element.getBooleanOrDefault("xVelocity", false));
        tntPhase.setYJump(element.getBooleanOrDefault("yVelocity", false));
        tntPhase.setZJump(element.getBooleanOrDefault("zVelocity", false));
        switch (element.getStringOrDefault("order", "REPEATER")) {
            case "REPEATER":
                tntPhase.setOrder(0);
                break;
            case "OBSERVER":
                tntPhase.setOrder(1);
                break;
            case "COMPARATOR":
                tntPhase.setOrder(2);
                break;
        }
        return tntPhase;
    }
}
