package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.VdcDriver;
import com.bocloud.cmp.driver.compute.ClusterDriver;
import com.bocloud.cmp.driver.network.NetworkDriver;
import com.bocloud.cmp.driver.storage.DataStoreDriver;
import com.bocloud.cmp.model.VdcBean;
import com.bocloud.common.enums.BaseStatus;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.KeyGenerator;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.common.MathUtils;
import com.bocloud.ims.entity.common.VendorSyncRecord;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.VdcService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.transportor.SingleVmwareTransportor;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service("vdcService")
public class VdcServiceImpl implements VdcService {

    private static final Logger logger = LoggerFactory.getLogger(VdcServiceImpl.class);
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private VdcDriver vdcDriver;
    @Autowired
    private ClusterDriver clusterDriver;
    @Autowired
    private NetworkDriver networkDriver;
    @Autowired
    private DataStoreDriver dataStoreDriver;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private PortGroupRepository portGroupRepository;
    @Autowired
    private IpPoolPortGroupRepository ipPoolPortGroupRepository;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;

    /**
     * @since 2018-05-18 modify by sxp 磁盘容量四舍五入保留两位小数
     */
    @Override
    public BocloudResult<GridBean<Vdc>> list(Pager pager) {
        GridBean gridBean = null;
        try {
            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();

            if (null == params) {
                params = Lists.newArrayList();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            int total = this.vdcRepository.count(params);
            if (simple) {
                List<SimpleBean> beans = this.vdcRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                Long vendorId = null;
                for (Param param : params) {
                    if (param.getSign() == Sign.EQ) {
                        for (String key : param.getParam().keySet()) {
                            if ("vendorId".equals(key) && !StringUtils.isEmpty(param.getParam().get(key).toString())) {
                                vendorId = Long.valueOf(param.getParam().get(key).toString());
                                break;
                            }
                        }
                    }
                }
                // 获取实时的数据中心的资源使用量
                List<Vdc> allVdcs = Lists.newArrayList();
                if (null != vendorId) {
                    CloudVendor vendor = cloudVendorRepository.query(vendorId);
                    if (null != vendor) {
                        BocloudResult result = vdcDriver.list(vendor.getUuid());
                        if (null != result.getData()) {
                            String content = JSONObject.toJSONString(result.getData());
                            allVdcs.addAll(JSONObject.parseArray(content, Vdc.class));
                        }
                    }
                }

                Map<String, Vdc> vdcMap = Maps.newHashMap();
                for (Vdc vdc : allVdcs) {
                    vdcMap.put(vdc.getVdcVal(), vdc);
                }

                Map<Long, List<Cluster>> clusterMap = clusterRepository.listByVendor(vendorId).stream()
                        .filter(cluster -> null != cluster.getVdcId()).collect(Collectors.groupingBy(Cluster::getVdcId));
                Map<Long, List<Server>> serverMap = serverRepository.listByVendor(vendorId).stream()
                        .filter(server -> null != server.getVdcId()).collect(Collectors.groupingBy(Server::getVdcId));
                // 数据库和实时情况进行比较，如果存在，则显示实时的情况
                List<Vdc> list = this.vdcRepository.list(page, rows, params, sorter);
                for (Vdc vdc : list) {
                    if (vdcMap.containsKey(vdc.getVdcVal())) {
                        Vdc newVdc = vdcMap.get(vdc.getVdcVal());
                        vdc.setCpuTotal(newVdc.getCpuTotal());
                        vdc.setCpuUsed(newVdc.getCpuUsed());
                        vdc.setMemTotal(newVdc.getMemTotal());
                        vdc.setMemUsed(newVdc.getMemUsed());
                        vdc.setDiskTotal(MathUtils.round(newVdc.getDiskTotal(), 2));
                        vdc.setDiskUsed(MathUtils.round(newVdc.getDiskUsed(), 2));
                    }
                    vdc.setClusterNum((long) Optional.ofNullable(clusterMap.get(vdc.getId())).orElse(new ArrayList<>()).size());
                    vdc.setHostNum((long) Optional.ofNullable(serverMap.get(vdc.getId())).orElse(new ArrayList<>()).size());
                }
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query vdc list fail:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<Vdc> create(Vdc vdc) {
        try {
            vdc.setStatus(BaseStatus.NORMAL.name());
            if (null == vdc.getUuid()) {
                vdc.setUuid(KeyGenerator.uuid());
            }
            vdcRepository.save(vdc);
        } catch (Exception e) {
            logger.error("Create vdc fail:", e);
            return new BocloudResult<>(false, "添加失败");
        }
        return new BocloudResult<>(true, vdc, "添加成功");
    }

    @Override
    public BocloudResult<Vdc> modify(VdcBean bean, Long userId) {
        String path = Vdc.class.getSimpleName() + "_" + bean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Vdc vdc = this.vdcRepository.query(bean.getId());
            if (null == vdc) {
                logger.warn("Vdc does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            BeanUtils.copyProperties(bean, vdc);
            vdc.setMenderId(userId);
            this.vdcRepository.update(vdc);
            return new BocloudResult<>(true, "修改成功");
        } catch (Exception e) {
            logger.error("Modify vdc fail:", e);
            return new BocloudResult<>(false, "修改失败");
        }
    }

    @Override
    public BocloudResult remove(Long id, Long userId) {
        String path = Vdc.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Vdc object = this.vdcRepository.query(id);
            if (null == object) {
                logger.warn("Vdc does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            this.vdcRepository.remove(id, userId);
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Remove vdc error:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

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

    @Override
    public BocloudResult<List<Server>> listHost(Long id) {
        try {
            List<Server> hosts = this.serverRepository.listByVdc(id);
            List<Server> list = Lists.newArrayList();
            for (Server host : hosts) {
                List<NetworkCard> cards = Lists.newArrayList();
                List<NetworkCard> netCards = networkCardRepository.listByHost(host.getId(), "PM");
                for (NetworkCard card : netCards) {
                    if (null != card.getUsed() && !card.getUsed()) {
                        cards.add(card);
                    }
                }
                if (!cards.isEmpty()) {
                    host.setNetcards(cards);
                    list.add(host);
                }
            }
            return new BocloudResult<>(true, list, "查询详情成功");
        } catch (Exception e) {
            logger.error("List host by vdc error:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult syncByVdc(Long id, String type, RequestContext context) {
        try {
            Vdc vdc = vdcRepository.query(id);
            if (null == vdc) {
                logger.error("数据中心不存在!");
                return new BocloudResult(false, "数据中心不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(vdc.getVendorId());
            if (null == vendor) {
                logger.error("平台不存在!");
                return new BocloudResult(false, "平台不存在");
            }
            // 启动一个线程
            new Thread(() -> {
                String typeName = "";
                if ("cluster".equalsIgnoreCase(type)) {
                    typeName = "主机集群";
                } else if ("network".equalsIgnoreCase(type)) {
                    typeName = "网络";
                } else if ("datastore".equalsIgnoreCase(type)) {
                    typeName = "数据存储";
                }
                Date startTime = new Date();
                String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId();
                String operate = vendor.getType().toLowerCase() + ".sync";
                BocloudResult result = new BocloudResult(false, "暂不支持");
                OperateResult operateResult = new OperateResult(true, typeName + "同步成功", operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                    CloudVendor cloudVendor = cloudVendorRepository.query(vendor.getId());
                    if (null == cloudVendor) {
                        logger.error("平台数据不存在!");
                        result = new BocloudResult(false, "平台数据不存在!");
                        operateResult.setSuccess(false);
                        operateResult.setMessage("平台数据不存在！");
                    }
                    if (operateResult.isSuccess()) {
                        String vendorUuid = vendor.getUuid();
                        String vendorName = vendor.getName();
                        String vdcName = vdc.getName();
                        logger.info("开始执行平台{} 数据中心{} 的{} 同步操作", vendorName, vdcName, typeName);
                        if ("cluster".equalsIgnoreCase(type)) {
                            result = clusterDriver.listByVdc(vendorUuid, vdcName);
                        } else if ("network".equalsIgnoreCase(type)) {
                            result = networkDriver.listByVdc(vendorUuid, vdcName);
                        } else if ("datastore".equalsIgnoreCase(type)) {
                            result = dataStoreDriver.listByVdc(vendorUuid, vdcName);
                        }
                        if (result.isSuccess()) {
                            SingleVmwareTransportor tool = new SingleVmwareTransportor(
                                    vdcRepository, clusterRepository, dataStoreRepository,
                                    networkRepository, networkCardRepository,
                                    switcherRepository, portGroupRepository, ipPoolPortGroupRepository,
                                    amqpTemplate, poolGroupRelationRepository);
                            result = tool.syncByVdc(vendor, vdc, type, typeName, result.getData(), context.getTarget());
                        }
                    }
                    logger.info(typeName + "同步任务结果：{}", result.getMessage());
                    operateResult.setSuccess(result.isSuccess());
                    operateResult.setMessage(result.getMessage());
                } catch (Exception e) {
                    logger.error(typeName + "同步任务异常", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage(typeName + "同步任务异常");
                }
                resourceEventPublisher.send(operateResult);
                VendorSyncRecord record = new VendorSyncRecord();
                record.setVendorId(vendor.getId());
                record.setStartTime(startTime);
                record.setEndTime(new Date());
                record.setCost(record.getEndTime().getTime() - startTime.getTime());
                record.setResult(operateResult.getMessage());
                record.setCreatorId(context.getTarget());
                record.setSyncResult(operateResult.isSuccess());
                record.setAuto(false);
                amqpTemplate.convertAndSend("vendor.record.queue", record);
                if (operateResult.isSuccess()) {
                    // 发送给云平台统计队列对云平台重新统计
                    JSONObject object = new JSONObject();
                    object.put(Common.VENDORID, vendor.getId());
                    amqpTemplate.convertAndSend("vendor.statistics.queue", object);
                }
                // 更新云平台最后一次同步时间
                vendor.setGmtModify(record.getEndTime());
                vendor.setMenderId(context.getTarget());
                cloudVendorRepository.update(vendor);
            }).start();
            return new BocloudResult(true, "同步任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("sync vdc operation exception ", e);
            return new BocloudResult(false, "同步失败!");
        }
    }

}
