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

import lombok.NonNull;
import org.bukkit.Location;

import javax.annotation.CheckReturnValue;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;

public interface RegionSystem {

    RegionSystem INSTANCE = init();

    /**
     * Loads and initializes the Regions and anything that should be loaded on startup.
     */
    void load();

    /**
     * Saves anything that should be written to file on either CRIUSleepEvent or plugin disable.
     */
    void save();

    /**
     * Returns the Location to teleport players to when they first join or Warp to "WorldSpawn"
     */
    @NonNull
    Location getWorldSpawn();

    /**
     * Returns the GlobalRegion. This Region should have their {@link Region#getID()} return the
     * '00000000-0000-0000-0000-000000000000' UUID for easier retrieval with {@link #getRegion(UUID)}.
     */
    @NonNull
    Region getGlobalRegion();

    /**
     * Should return a Region that is present at the specific Location or the {@link #getGlobalRegion()}
     * if none are present.
     */
    @NonNull
    Region get(@NonNull Location location);

    /**
     * Should return the Region by their UUID.
     */
    @CheckReturnValue
    Optional<Region> getRegion(@NonNull UUID id);

    /**
     * Does and should not contain the GlobalRegion returned by {@link #getGlobalRegion()}.
     */
    @NonNull
    Stream<Region> getRegions();

    private static RegionSystem init() {
        try {
            return (RegionSystem) Class.forName("de.steamwar.bausystem.region.DynamicRegionSystem").getConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            // Ignore
        }
        try {
            return (RegionSystem) Class.forName("de.steamwar.bausystem.region.FixedRegionSystem").getConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            return new RegionSystem() {
                @Override
                public void load() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public void save() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public @NonNull Location getWorldSpawn() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Region getGlobalRegion() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Region get(Location location) {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Optional<Region> getRegion(UUID id) {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Stream<Region> getRegions() {
                    throw new UnsupportedOperationException();
                }
            };
        }
    }
}
