package dev.photosync.mcapi.lifecycle;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * The gate a mixin on the game's exit path asks before letting the process go
 * away.
 *
 * <p>A screenshot that was still uploading when the player pressed "Quit Game"
 * is the one case where doing nothing loses data the player can see they took.
 * The queue is durable, so nothing is truly lost, but "it will finish next time
 * you play" is a worse answer than "give it four more seconds", and the player
 * cannot make that choice unless something stops the shutdown long enough to ask.
 *
 * <p>Static for the same reason as {@code ScreenshotBus}: the caller is woven
 * into a Minecraft class and has nothing to be injected with. Both are confined
 * to {@code mc-api} so the rest of the mod stays constructor-wired.
 *
 * <p>The protocol is deliberately one-shot. Once the player has answered -- by
 * waiting or by insisting -- {@link #allowOnce()} opens the gate for exactly the
 * next attempt, so a second quit later in the session is questioned again.
 */
@Slf4j
public final class QuitGuard {

    private static final QuitGuard INSTANCE = new QuitGuard();

    /** Answers whether the game may shut down, and takes over the interaction if not. */
    @FunctionalInterface
    public interface Handler {
        boolean mayQuit();
    }

    private final AtomicBoolean approved = new AtomicBoolean();
    private volatile Handler handler = () -> true;

    private QuitGuard() {
    }

    public static QuitGuard get() {
        return INSTANCE;
    }

    /** Installed once, at client startup. */
    public void handler(Handler handler) {
        this.handler = handler;
    }

    /**
     * Called from the exit path. {@code false} means PhotoSync has taken over
     * and the mixin should cancel the shutdown; the mod will come back through
     * here once the player has decided.
     */
    public boolean mayQuit() {
        if (approved.getAndSet(false)) {
            return true;
        }
        try {
            return handler.mayQuit();
        } catch (RuntimeException e) {
            // Never trap the player in a game that will not close.
            log.error("The quit handler failed; letting the game shut down", e);
            return true;
        }
    }

    /** Lets exactly the next {@link #mayQuit()} through. */
    public void allowOnce() {
        approved.set(true);
    }
}
