package cd.casic.ci.process.ssh;

import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.utils.CryptogramUtil;
import io.cloudsoft.winrm4j.client.WinRmClientContext;
import io.cloudsoft.winrm4j.winrm.WinRmTool;
import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.List;

/**
 * @author herenbin
 * @date 2023/6/26
 */
@Slf4j
public class WinRMHelper {

    private final String ip;

    private final String username;

    private final String password;

    public static final int DEFAULT_PORT = WinRmTool.DEFAULT_WINRM_PORT;

    public WinRMHelper(final String ip, final String username, final String password) {
        this.ip = ip;
        this.username = username;
        this.password = password;
    }

    public WinRMHelper(MachineInfoDO machineInfo) {
        this.ip = machineInfo.getHostIp();
        this.username = machineInfo.getUsername();
        this.password = CryptogramUtil.doDecrypt(machineInfo.getPassword());
    }

    public int execute(final String command, ExecCallback execCallback) {
        WinRmClientContext context = WinRmClientContext.newInstance();
        try {
            WinRmTool tool = WinRmTool.Builder.builder(ip, username, password)
                    .port(DEFAULT_PORT).useHttps(false).context(context).build();
            tool.setOperationTimeout(5000L);
            WinRmToolResponse resp = tool.executeCommand(command);
            int statusCode = resp.getStatusCode();
            execCallback.callback(resp.getStdOut());
            String stdErr = resp.getStdErr();
            if (StringUtils.isNotEmpty(stdErr)) {
                execCallback.callback(stdErr);
            }
            return statusCode;
        } finally {
            context.shutdown();
        }
    }

    public int execute(final List<String> commandList, ExecCallback execCallback) {
        WinRmClientContext context = WinRmClientContext.newInstance();
        WinRmTool tool = WinRmTool.Builder.builder(ip, username, password)
                .port(DEFAULT_PORT).useHttps(false).context(context).build();
        tool.setOperationTimeout(5000L);

        WinRmToolResponse resp = tool.executeCommand(commandList);

        StringReader reader = new StringReader(resp.getStdOut() + resp.getStdErr());
        try {
            char[] buffer = new char[1024];
            int output;
            while ((output = reader.read(buffer)) != -1) {
                execCallback.callback(new String(buffer, 0, output));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        int statusCode = resp.getStatusCode();
        context.shutdown();
        return statusCode;
    }

    public int executePs(final List<String> commandList, ExecCallback execCallback) {
        WinRmClientContext context = WinRmClientContext.newInstance();
        WinRmTool tool = WinRmTool.Builder.builder(ip, username, password)
                .port(DEFAULT_PORT).useHttps(false).context(context).build();
        tool.setOperationTimeout(5000L);

        WinRmToolResponse resp = tool.executePs(commandList);

        StringReader reader = new StringReader(resp.getStdOut() + resp.getStdErr());
        try {
            char[] buffer = new char[1024];
            int output;
            while ((output = reader.read(buffer)) != -1) {
                execCallback.callback(new String(buffer, 0, output));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        int statusCode = resp.getStatusCode();
        context.shutdown();
        return statusCode;
    }

    public String execute(final List<String> commandList, ExecCallback execCallback, String pass) {
        WinRmClientContext context = WinRmClientContext.newInstance();
        WinRmTool tool = WinRmTool.Builder.builder(ip, username, password)
                .port(DEFAULT_PORT).useHttps(false).context(context).build();
        tool.setOperationTimeout(5000L);
        WinRmToolResponse resp = tool.executeCommand(commandList);
        context.shutdown();
        return resp.getStdOut();
    }

    private String join(List<String> commands) {
        StringBuilder builder = new StringBuilder();
        boolean first = true;
        for (String command : commands) {
            if (first) {
                first = false;
            } else {
                builder.append(" & ");
            }
            builder.append(command);
        }
        return builder.toString();
    }
}
