package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.HostDriver;
import com.bocloud.cmp.model.HostOperateModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Cluster;
import com.bocloud.ims.entity.resource.ClusterNode;
import com.bocloud.ims.entity.resource.Region;
import com.bocloud.ims.interfaces.resource.ClusterNodeService;
import com.bocloud.ims.interfaces.resource.SyncService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ClusterNodeRepository;
import com.bocloud.ims.repository.resource.ClusterRepository;
import com.bocloud.ims.repository.resource.RegionRepository;
import com.bocloud.ims.service.config.JenkinsConfiguration;
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.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service("clusterNodeService")
public class ClusterNodeServiceImpl implements ClusterNodeService {

    private static final Logger logger = LoggerFactory.getLogger(ClusterNodeServiceImpl.class);
    @Autowired
    private ClusterNodeRepository clusterNodeRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private RegionRepository regionRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private HostDriver hostDriver;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private JenkinsConfiguration jenkinsConfiguration;
    @Autowired
    private SyncService syncService;
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public BocloudResult<GridBean<ClusterNode>> list(Pager pager) {
        GridBean gridBean = null;
        try {
            pager.getSorter().put("gmtCreate", Common.ONE);
            int total = this.clusterNodeRepository.count(pager.getParams());
            if (pager.getSimple()) {
                List<SimpleBean> beans = this.clusterNodeRepository.list(pager.getParams(), pager.getSorter());
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                List<ClusterNode> list = this.clusterNodeRepository.list(pager.getPage(), pager.getRows(), pager.getParams(), pager.getSorter());
                gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query cluster list fail:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<ClusterNode> detail(Long id) {
        try {
            ClusterNode node = this.clusterNodeRepository.query(id);
            Assert.notNull(node, "数据不存在");
            return new BocloudResult<>(true, node, "查询详情成功");
        } catch (Exception e) {
            logger.error("Get cluster error：", e);
            return new BocloudResult<>(false, "查询详情失败");
        }
    }

    public BocloudResult<List<ClusterNode>> listAddHost(String params) {
        try {
            JSONObject jsonObject = JSONTools.isJSONObj(params);
            Assert.notNull(jsonObject, "参数异常");
            Long clusterId = jsonObject.getLong("clusterId");// 云平台ID
            Cluster cluster = clusterRepository.query(clusterId);
            Assert.notNull(cluster, "主机组不存在！");
            Region region = regionRepository.query(cluster.getRegionId());
            Assert.notNull(region, "区域不存在！");
            CloudVendor cloudVendor = cloudVendorRepository.query(cluster.getVendorId());
            Assert.notNull(cloudVendor, "平台信息错误！");
            List<ClusterNode> clusterNodes = clusterNodeRepository.listAddHost(cloudVendor.getId(), region.getName());
            return new BocloudResult<>(true, clusterNodes, "查询成功！");
        } catch (Exception e) {
            logger.error("查询失败：" + e.getMessage());
            return new BocloudResult<>(false, "查询失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<ClusterNode>> condition(String condition) {
        JSONObject object = JSONObject.parseObject(condition);
        String action = object.getString("condition");
        if ("listAddHost".equalsIgnoreCase(action)) {
            return listAddHost(condition);
        }
        if ("listRemoveHost".equalsIgnoreCase(action)) {
            return listRemoveHost(condition);
        }
        return null;
    }

    private BocloudResult<List<ClusterNode>> listRemoveHost(String params) {
        try {
            JSONObject jsonObject = JSONTools.isJSONObj(params);
            Assert.notNull(jsonObject, "参数异常");
            Long clusterId = jsonObject.getLong("clusterId");// 云平台ID
            Cluster cluster = clusterRepository.query(clusterId);
            Assert.notNull(cluster, "主机组不存在！");
            Region region = regionRepository.query(cluster.getRegionId());
            Assert.notNull(region, "区域不存在！");
            CloudVendor cloudVendor = cloudVendorRepository.query(cluster.getVendorId());
            Assert.notNull(cloudVendor, "平台信息错误！");
            List<ClusterNode> clusterNodes = clusterNodeRepository.listRemoveHost(clusterId, cloudVendor.getId(),
                    null);
            return new BocloudResult<>(true, clusterNodes, "查询成功！");
        } catch (Exception e) {
            logger.error("查询失败：" + e.getMessage());
            return new BocloudResult<>(false, "查询失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = ClusterNode.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            ClusterNode clusterNode = clusterNodeRepository.query(id);
            Assert.notNull(clusterNode, "数据不存在！");
            CloudVendor cloudVendor = cloudVendorRepository.query(clusterNode.getVendorId());
            Assert.notNull(cloudVendor, "平台验证失败");
            new Thread(() -> {
                String operate = cloudVendor.getType().toLowerCase() + ".host";
                String content = "删除失败！";
                BocloudResult bocloudResult = new BocloudResult<>(false, content);
                try {
                    HostOperateModel model = new HostOperateModel();
                    bocloudResult = hostDriver.remove(cloudVendor.getUuid(), clusterNode.getZone(), model);
                    if (bocloudResult.isSuccess()) {
                        clusterNodeRepository.remove(id, context.getTarget());
                    } else {
                        content = bocloudResult.getMessage();
                    }
                } catch (Exception e) {
                    content = e.getMessage();
                }
                resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), content, operate,
                        MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
                        OperateResult.OperateCategory.ResourceEvent, context));
            }).start();
            return new BocloudResult<>(true, "主机删除成功");
        } catch (Exception e) {
            logger.error("remove host fail:", e);
            return new BocloudResult<>(false, "主机删除失败", null, null);
        }
    }

    /**
     * 添加计算节点 添加计算节点： curl -d
     * 'SALT_MASTER_URL=SALT_MASTER_URL&TARGET_SERVERS=cmp002*' -k -X POST
     * JENKINS_URL/job/deploy-openstack-compute/buildWithParameters \   --user
     * USER:TOKEN
     */
    @Override
    public BocloudResult create(ClusterNode clusterNode, RequestContext context) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(clusterNode.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            new Thread(() -> {
                BocloudResult result = new BocloudResult<>(false, "创建失败！");
                String operate = vendor.getType().toLowerCase() + ".host";
                String content = "申请主机任务失败";
                try {
                    String job = "deploy-openstack-compute";
                    Map<String, String> params = new HashMap<>();
                    params.put("SALT_MASTER_URL", clusterNode.getSaltMasterUrl());// https://10.6.4.15:8969
                    params.put("TARGET_SERVERS", clusterNode.getTargetServers());// cmp004*
                    logger.info(JSON.toJSONString(params));
                    Integer createJob = jenkinsConfiguration.createJob(job, params);
                    BocloudResult createResult = jenkinsConfiguration.createResult(createJob, job);
                    if (createResult.isSuccess()) {
                        syncService.sync(vendor.getId(), context, true);
                        Thread.sleep(1000 * 60 * 5L);
                        result = new BocloudResult<>(true, "主机创建成功！");
                        content = "主机创建成功！";
                    } else {
                        content = createResult.getMessage();
                    }
                } catch (Exception e) {
                    content = e.getMessage();
                }
                // 发送给云平台统计队列对云平台重新统计
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Common.VENDORID, vendor.getId());
                amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
                resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                        MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                        OperateResult.OperateCategory.ResourceEvent, context));
            }).start();
            return new BocloudResult<>(true, "申请创建计算主机任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("Get error message:", e);
            return new BocloudResult<>(false, "创建失败");
        }
    }
}
