package com.bocloud.ims.service.resource.powervc;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.ValidateDriver;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.powervc.ValidateResult;
import com.bocloud.ims.interfaces.resource.powervc.ValidateService;
import com.bocloud.ims.repository.powervc.ValidateResultRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * powervc中验证环境服务实现类
 *
 * @author lkx007
 */
@Service
public class ValidateServiceImpl implements ValidateService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final String operate = "validate.result";
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ValidateDriver validateDriver;
    @Autowired
    private ValidateResultRepository validateResultRepository;
    @Autowired
    private CloudVendorRepository vendorRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @Override
    public BocloudResult<GridBean<ValidateResult>> listResult(Pager pager) {
        try {
            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();

            int total = validateResultRepository.count(params);
            List<ValidateResult> list = validateResultRepository.list(page, rows, params, sorter);
            GridBean gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult(true, gridBean, "查询验证环境结果成功");
        } catch (Exception e) {
            logger.error("查询验证环境结果失败：", e);
            return new BocloudResult(false, "查询验证环境结果失败");
        }
    }

    @Override
    public BocloudResult env(Long vendorId, RequestContext context) {
        try {
            CloudVendor vendor = vendorRepository.query(vendorId);
            if (vendor == null) {
                logger.error("vendor id = [{}]不存在", vendorId);
                return new BocloudResult(false, "未找到平台");
            }
            validateResultRepository.deleteByVendorId(vendorId);
            taskExecutor.submit(() -> {
                OperateResult result = new OperateResult(true, "", operate, null, OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(CloudVendor.class.getSimpleName() + "_" + vendorId + "_ENV")){
                    // 先检查锁，验证环境任务不可重复下发
                    if (!lock.acquire()) {
                        result.setSuccess(false);
                        result.setMessage("已有验证环境任务正在执行，请稍后");
                        resourceEventPublisher.send(result);
                        return;
                    }
                    // 下发验证环境任务
                    BocloudResult bocloudResult = validateDriver.validate(vendor.getUuid());
                    if (bocloudResult.isFailed()) {
                        logger.error("下发验证环境任务到powervc失败:", bocloudResult.getMessage());
                        result.setSuccess(false);
                        result.setMessage("下发验证环境任务到powervc失败:" + bocloudResult.getMessage());
                        resourceEventPublisher.send(result);
                        return;
                    }
                    // 将验证环境结果实时入库
                    long start = System.currentTimeMillis();
                    boolean successed = false;
                    while (System.currentTimeMillis() - start < 1000 * 60 * 10) {
                        bocloudResult = validateDriver.result(vendor.getUuid());
                        if (bocloudResult.isFailed()) {
                            logger.warn("查询验证环境结果失败:", bocloudResult.getMessage());
                            continue;
                        }
                        // 数据入库
                        List<ValidateResult> validateResults = new ArrayList<>();
                        JSONObject jsonObject = (JSONObject) bocloudResult.getData();
                        JSONArray priorResults = jsonObject.getJSONArray("prior-results");
                        for (int i = 0; i < priorResults.size(); i++) {
                            JSONObject priorResult = priorResults.getJSONObject(i);
                            // 获取结束时间
                            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                            Date stopTime = simpleDateFormat.parse(priorResult.getString("stop-time"));
                            // 将检查结果循环入库
                            JSONObject checkGroups = priorResult.getJSONObject("check-groups");
                            for (Map.Entry<String, Object> checkGroupEntry : checkGroups.entrySet()) {
                                JSONObject checkGroup = (JSONObject) checkGroupEntry.getValue();
                                JSONArray checks = checkGroup.getJSONArray("checks");
                                for (int j = 0; j < checks.size(); j++) {
                                    JSONObject check = checks.getJSONObject(j);
                                    ValidateResult validateResult = new ValidateResult();
                                    validateResult.setGmtCreate(stopTime);
                                    validateResult.setCheckId(check.getString("val_check_id"));
                                    validateResult.setMsg(check.getString("msg"));
                                    validateResult.setMsgId(check.getString("msg-id"));
                                    validateResult.setSystem(check.getString("ip"));
                                    validateResult.setSolution(check.getString("response"));
                                    validateResult.setStatus(check.getString("status"));
                                    validateResult.setGroupDescription(checkGroup.getString("group-description"));
                                    validateResult.setVendorId(vendorId);
                                    validateResults.add(validateResult);
                                }
                            }
                        }

                        TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
                        try {
                            validateResultRepository.deleteByVendorId(vendorId);
                            for (ValidateResult validateResult : validateResults) {
                                validateResultRepository.save(validateResult);
                            }
                            platformTransactionManager.commit(transaction);
                        } catch (Exception e) {
                            platformTransactionManager.rollback(transaction);
                            logger.warn("保存验证环境结果失败:", e.getMessage());
                            continue;
                        }
                        // 判断是否执行完成
                        JSONArray executingTasks = jsonObject.getJSONArray("executing-tasks");
                        if (executingTasks.size() == 0) {
                            successed = true;
                            break;
                        } else {
                            int completeCategories = executingTasks.getJSONObject(0).getInteger("completed-categories");
                            int totalCategories = executingTasks.getJSONObject(0).getInteger("total-categories");
                            if (completeCategories == totalCategories) {
                                successed = true;
                                break;
                            }
                        }
                        int percent = executingTasks.getJSONObject(0).getJSONObject("status").getInteger("percent-complete-estimate");
                        logger.info("正在验证环境，当前进度为：" + percent + "%，3秒后继续检测...");
                        // 等待三秒
                        Thread.sleep(3000);
                    }
                    if (successed) {
                        logger.info("验证环境任务执行完成");
                        result.setSuccess(true);
                        result.setMessage("验证环境任务执行成功");
                        resourceEventPublisher.send(result);
                        return;
                    } else {
                        logger.info("验证环境任务执行超时");
                        result.setSuccess(false);
                        result.setMessage("验证环境任务执行超时");
                        resourceEventPublisher.send(result);
                        return;
                    }
                } catch (Exception e) {
                    logger.error("验证环境失败:", e);
                    result.setSuccess(true);
                    result.setMessage("验证环境任务执行失败：" + e.getMessage());
                    resourceEventPublisher.send(result);
                }
            });
            return new BocloudResult(true, "验证环境任务下发成功，正在执行...");
        } catch (Exception e) {
            logger.error("验证环境失败：", e);
            return new BocloudResult(false, "验证环境失败");
        }
    }
}
