package p.packer.services;

import p.packer.messages.PackerProjectContext;
import p.packer.models.PackerRuntimeSnapshot;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;

public final class PackerProjectRuntime {
    private final PackerProjectContext project;
    private final AtomicReference<PackerRuntimeSnapshot> snapshot;
    private final AtomicBoolean disposed = new AtomicBoolean(false);

    public PackerProjectRuntime(PackerProjectContext project, PackerRuntimeSnapshot initialSnapshot) {
        this.project = Objects.requireNonNull(project, "project");
        this.snapshot = new AtomicReference<>(Objects.requireNonNull(initialSnapshot, "initialSnapshot"));
    }

    public PackerProjectContext project() {
        return project;
    }

    public PackerRuntimeSnapshot snapshot() {
        ensureActive();
        return snapshot.get();
    }

    public void replaceSnapshot(PackerRuntimeSnapshot nextSnapshot) {
        ensureActive();
        snapshot.set(Objects.requireNonNull(nextSnapshot, "nextSnapshot"));
    }

    public PackerRuntimeSnapshot updateSnapshot(UnaryOperator<PackerRuntimeSnapshot> updater) {
        ensureActive();
        return snapshot.updateAndGet(current -> Objects.requireNonNull(
                Objects.requireNonNull(updater, "updater").apply(current),
                "updatedSnapshot"));
    }

    public boolean disposed() {
        return disposed.get();
    }

    public void dispose() {
        disposed.set(true);
    }

    private void ensureActive() {
        if (disposed.get()) {
            throw new IllegalStateException("Runtime has been disposed for project: " + project.projectId());
        }
    }
}
