package io.xpipe.app.process;

import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEventFactory;

import lombok.SneakyThrows;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class LocalShell {

    private static ShellControl local;
    private static ShellControl localPowershell;
    private static boolean powershellInitialized;
    private static final Map<Object, ShellControl> localShellInstances = new HashMap<>();

    public static synchronized ShellControl get(Object key) throws Exception {
        var found = localShellInstances.get(key);
        if (found != null) {
            return found;
        }

        var sc = ProcessControlProvider.get().createLocalProcessControl(true).start();
        localShellInstances.put(key, sc);
        return sc;
    }

    public static synchronized boolean isInitialized() {
        return local != null;
    }

    public static synchronized ShellControl init() throws Exception {
        if (local == null) {
            local = ProcessControlProvider.get()
                    .createLocalProcessControl(false)
                    .start();
        }
        return local;
    }

    public static synchronized void reset(boolean force) {
        if (local != null) {
            if (!force) {
                try {
                    local.exitAndWait();
                } catch (Exception e) {
                    ErrorEventFactory.fromThrowable(e).omit().handle();
                    local.kill();
                }
            } else {
                local.kill();
            }
            local = null;
        }
        if (localPowershell != null) {
            if (!force) {
                try {
                    localPowershell.exitAndWait();
                } catch (Exception e) {
                    ErrorEventFactory.fromThrowable(e).omit().handle();
                    localPowershell.kill();
                }
            } else {
                localPowershell.kill();
            }
            localPowershell = null;
        }
    }

    public static synchronized Optional<ShellControl> getLocalPowershell() {
        if (local != null && ShellDialects.isPowershell(local)) {
            return Optional.of(local);
        }

        try {
            if (powershellInitialized) {
                return Optional.ofNullable(localPowershell != null ? localPowershell.start() : null);
            }

            powershellInitialized = true;
            localPowershell = ProcessControlProvider.get()
                    .createLocalProcessControl(false)
                    .subShell(ShellDialects.POWERSHELL)
                    .start();
            localPowershell.getShellDialect().getDumbMode().throwIfUnsupported();
        } catch (Exception ex) {
            localPowershell = null;
            ErrorEventFactory.fromThrowable(ex)
                    .description("Failed to start local powershell process")
                    .handle();
        }

        return Optional.ofNullable(localPowershell);
    }

    @SneakyThrows
    public static ShellControl getShell() {
        if (local == null) {
            throw new IllegalStateException("Local shell not initialized yet");
        }

        return local.start();
    }

    public static ShellDialect getDialect() {
        return ProcessControlProvider.get().getEffectiveLocalDialect();
    }
}
