package p.studio.lsp.services;

import p.studio.lsp.api.LspServerLifecycle;
import p.studio.lsp.messages.LspProjectContext;
import p.studio.lsp.messages.LspServerConfiguration;
import p.studio.lsp.services.compiler.CompilerLanguageServiceBridge;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public final class LspServerLifecycleImpl implements LspServerLifecycle {
    private final TcpLspServerHostFactory serverHostFactory;
    private final CompilerLanguageServiceBridge compilerBridge;
    private final ConcurrentMap<String, TcpLspServerHost> activeServers;

    public LspServerLifecycleImpl() {
        this.compilerBridge = new CompilerLanguageServiceBridge();
        this.serverHostFactory = new TcpLspServerHostFactory();
        this.activeServers = new ConcurrentHashMap<>();
    }

    @Override
    public void bootServer(final LspServerConfiguration serverConfiguration, LspProjectContext context) {
        final var host = serverHostFactory.create(serverConfiguration, context, compilerBridge);
        final var previous = activeServers.putIfAbsent(context.projectKey(), host);
        if (previous != null) {
            throw new IllegalStateException("LSP server already booted for project " + context.projectKey());
        }

        try {
            host.start();
        } catch (RuntimeException runtimeException) {
            activeServers.remove(context.projectKey(), host);
            closeQuietly(host);
            throw runtimeException;
        }
    }

    @Override
    public void shutdownServer(final LspProjectContext project) {
        final var safeProject = Objects.requireNonNull(project, "project");
        final var host = activeServers.remove(safeProject.projectKey());
        if (host == null) {
            return;
        }
        closeQuietly(host);
    }

    private static void closeQuietly(final TcpLspServerHost host) {
        try {
            host.close();
        } catch (Exception exception) {
            throw new IllegalStateException("failed to close LSP host", exception);
        }
    }
}
