package com.bocloud.ims.service.internal.worker;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.BootOption;
import com.bocloud.cmp.entity.enums.NodeAction;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.common.utils.constant.Constant;
import com.bocloud.service.http.core.ServiceFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 请求worker阻塞获取mq中的worker执行的结果
 * <p>
 * 进行开关机、修改启动项等工作
 *
 * @author 007
 */
@Service("workerService")
public class WorkerService {
    private static final String IPMI_BOOT = "ipmi_boot";
    private static final String IPMI_POWER = "ipmi_power";
    private static final String BOOTDEV = "bootdev";
    private final static String POWER_V_2_0 = "ipmitool -I lanplus -U %s -P %s -p %s -H %s power status -R 1 -N 1";
    private final static String POWER_V_1_5 = "ipmitool -U %s -P %s -p %s -H %s power status -R 1 -N 1";
    private final static String ON = "Chassis Power is on";
    private final static String OFF = "Chassis Power is off";
    private static Logger logger = LoggerFactory.getLogger(WorkerService.class);
    @Autowired
    private ServiceFactory serviceFactory;
    @Autowired
    private RabbitAdmin rabbitAdmin;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * 调用worker执行开关机重启设置启动项等操作
     * <p>
     * 直接获得worker放到mq中的结果
     *
     * @param info
     * @param action
     * @return
     */
    public BocloudResult action(IpmiInfo info, NodeAction action) {
        return action(info, action, null);
    }

    /**
     * 调用worker执行开关机重启设置启动项等操作
     * <p>
     * queue为null，则阻塞，返回结果就是worker发送到mq的结果
     * <p>
     * queue不为null，不阻塞，返回结果为worker的http的返回，需要手动监听mq的队列获取worker的真正执行的结果
     *
     * @param info
     * @param action
     * @param queue
     * @return
     */
    public BocloudResult action(IpmiInfo info, NodeAction action, String queue) {
        Map<String, Object> decrypt = new HashMap<>(1);
        Map<String, Object> args = MapTools.simpleMap(Constant.NAME, info.getHost());
        args.put(Constant.USER, info.getUser());
        args.put(Constant.PSWD, "{{ " + Constant.IPMI_PSWD + " }}");
        args.put(Constant.PORT, info.getPort());
        decrypt.put(Constant.IPMI_PSWD, info.getPassword());
        Module<?> module;
        switch (action) {
            case on:
                args.put(Constant.STATE, NodeAction.on.name());
                module = new Module<>(IPMI_POWER, args, decrypt);
                break;
            case off:
                args.put(Constant.STATE, NodeAction.off.name());
                module = new Module<>(IPMI_POWER, args, decrypt);
                break;
            case shutdown:
                args.put(Constant.STATE, NodeAction.shutdown.name());
                module = new Module<>(IPMI_POWER, args, decrypt);
                break;
            case reset:
                args.put(Constant.STATE, NodeAction.reset.name());
                module = new Module<>(IPMI_POWER, args, decrypt);
                break;
            case boot:
                args.put(Constant.STATE, NodeAction.boot.name());
                module = new Module<>(IPMI_POWER, args, decrypt);
                break;
            case networkBoot:
                args.put(BOOTDEV, BootOption.NETWORK.name().toLowerCase());
                module = new Module<>(IPMI_BOOT, args, decrypt);
                break;
            case hdBoot:
                args.put(BOOTDEV, BootOption.HD.name().toLowerCase());
                module = new Module<>(IPMI_BOOT, args, decrypt);
                break;
            case opticalBoot:
                args.put(BOOTDEV, BootOption.OPTIONAL.name().toLowerCase());
                module = new Module<>(IPMI_BOOT, args, decrypt);
                break;
            case resetBoot:
                args.put(BOOTDEV, BootOption.DEFAULT.name().toLowerCase());
                module = new Module<>(IPMI_BOOT, args, decrypt);
                break;
            default:
                logger.error("不支持的物理机操作类型{}", action);
                return new BocloudResult(false, "不支持的物理机操作类型{}" + action);
        }
        List<WorkerHost> targets = new ArrayList<>();
        targets.add(new WorkerHost(Constant.LOCALHOST, "local"));
        RequestWorker client = new RequestWorker(targets, module, serviceFactory, rabbitAdmin, taskExecutor);
        if (queue == null) {
            return client.invoke();
        } else {
            return client.invoke(queue);
        }
    }

    /**
     * 调用worker检查ipmi信息是否正确
     *
     * @param info
     * @return
     */
    public BocloudResult check(IpmiInfo info) {
        if (!StringUtils.isNotEmpty(info.getHost()) || !StringUtils.isNotEmpty(info.getUser())
                || !StringUtils.isNotEmpty(info.getPassword())) {
            logger.warn("请求worker检查ipmi信息失败，ipmi信息[{}]不足", JSONObject.toJSONString(info));
            return new BocloudResult(false, "ipmi信息不足，无法检验");
        }
        // 支持默认port
        if (null == info.getPort()) {
            info.setPort(623);
        }
        String args = String.format(POWER_V_2_0,
                info.getUser(),
                "{{ " + Constant.IPMI_PSWD + " }}",
                info.getPort(),
                info.getHost()
        );
        Map<String, Object> decrypt = new HashMap<>(1);
        decrypt.put(Constant.IPMI_PSWD, info.getPassword());
        List<WorkerHost> targets = new ArrayList<>();
        targets.add(new WorkerHost(Constant.LOCALHOST, "local"));
        RequestWorker client = new RequestWorker(targets, new Module<>("raw", args, decrypt), serviceFactory, rabbitAdmin,
                taskExecutor);
        BocloudResult result = client.invoke();
        if (result.isFailed()) {
            // retry
            args = String.format(POWER_V_1_5, info.getUser(), info.getPassword(), info.getPort(), info.getHost());
            client = new RequestWorker(targets, new Module<>("raw", args, decrypt), serviceFactory, rabbitAdmin, taskExecutor);
            result = client.invoke();
            return result;
        }
        return result;
    }

    /**
     * 调用worker检查ipmi状态
     *
     * @param info
     * @return
     */
    public boolean check(IpmiInfo info, NodeAction action) {
        BocloudResult result = check(info);
        if (result.isFailed()) {
            return false;
        }
        if (NodeAction.on == action || NodeAction.reset == action) {
            // assert power status is on
            if (result.toString().contains(ON)) {
                return true;
            }
        }
        if (NodeAction.off == action) {
            // assert power status is off
            if (result.toString().contains(OFF)) {
                return true;
            }
        }
        // 不支持的action,返回false
        return false;
    }

}
