package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.model.DataCenterBean;
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.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.DataCenter;
import com.bocloud.ims.entity.resource.PoolGroupRelation;
import com.bocloud.ims.entity.resource.Rack;
import com.bocloud.ims.entity.resource.Room;
import com.bocloud.ims.interfaces.resource.DataCenterService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.utils.ParamHelper;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.api.client.util.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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接口实现类
 *
 * @author wei wei
 * @version 1.0
 * @since 2016.02.27
 */
@Service("dataCenterService")
public class DataCenterServiceImpl implements DataCenterService {

    private static Logger logger = LoggerFactory.getLogger(DataCenterServiceImpl.class);
    @Autowired
    private DataCenterRepository dataCenterRepository;
    @Autowired
    private RoomRepository roomRepository;
    @Autowired
    private RackRepository rackRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private DataStoreRepository storeRepository;
    @Autowired
    private DictionaryRepository dictionaryRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private ImageRepository imageRepository;

    /**
     * 校验数据中心面积
     *
     * @param dcId
     * @param totalArea
     * @return
     * @throws Exception
     */
    private BocloudResult checkArea(Long dcId, String totalArea) throws Exception {
        // 数据中心下总机房面积
        Long roomTotalArea = 0L;
        List<Room> rooms = roomRepository.queryByDcId(dcId);
        for (Room room : rooms) {
            Long roomTotal = org.springframework.util.StringUtils.isEmpty(room.getTotalArea()) ? 0
                    : Long.valueOf(room.getTotalArea());
            roomTotalArea += roomTotal;
        }
        if (StringUtils.isEmpty(totalArea) && roomTotalArea > 0L) {
            return new BocloudResult<>(false, "数据中心面积已被机房使用，不能置空");
        }
        Long newDcArea = StringUtils.isEmpty(totalArea) ? 0 : Long.valueOf(totalArea);
        if (newDcArea < roomTotalArea) {
            return new BocloudResult<>(false, "数据中心面积不能小于机房总面积");
        }
        return new BocloudResult<>(true, "校验通过");
    }

    @Override
    public BocloudResult<DataCenter> create(DataCenter dataCenter, Long userId) {
        try {
            // 判断中心名称是否重名
            boolean flag = dataCenterRepository.isNameRepeat(dataCenter.getName());
            if (flag) {
                return new BocloudResult<>(false, "中心名称已存在");
            }
            dataCenter.setCreatorId(userId);
            dataCenter.setMenderId(userId);
            dataCenter.setStatus(BaseStatus.NORMAL.name());
            dataCenter.setUsed("0");
            dataCenterRepository.save(dataCenter);
        } catch (Exception e) {
            logger.error("Create data center fail:", e);
            return new BocloudResult<>(false, e.getMessage(), "", "");
        }
        return new BocloudResult<>(true, dataCenter, "添加成功");
    }

    @Override
    public BocloudResult<DataCenter> modify(DataCenterBean bean, Long userId) {
        String path = DataCenter.class.getSimpleName() + "_" + bean.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            DataCenter center = this.dataCenterRepository.query(bean.getId());
            Assert.notNull(center, "数据不存在");
            // 判断中心名称是否重名
            if (!center.getName().equals(bean.getName())) {
                boolean flag = dataCenterRepository.isNameRepeat(bean.getName());
                if (flag) {
                    return new BocloudResult<>(false, "中心名称已存在");
                }
            }
            BocloudResult checkResult = this.checkArea(center.getId(), bean.getTotalArea());
            Assert.isTrue(checkResult.isSuccess(), checkResult.getMessage());
            BeanUtils.copyProperties(bean, center);
            center.setMenderId(userId);
            this.dataCenterRepository.update(center);
            return new BocloudResult<>(true, center, "修改成功");
        } catch (Exception e) {
            logger.error("Modify data center fail:", e);
            return new BocloudResult<>(false, e.getMessage(), null, null);
        }
    }

    @Override
    public BocloudResult remove(Long id, Long userId) {
        String path = DataCenter.class.getSimpleName() + "_" + id;
        int count = 0;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            DataCenter bean = this.dataCenterRepository.getDCBean(id);
            Assert.notNull(bean, "数据不存在");
            List<CloudVendor> vendors = cloudVendorRepository.listByDcId(id);
            if (!ListTool.isEmpty(vendors)) {
                return new BocloudResult<>(false, "该数据中心下存在云平台，请先删除");
            }
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(Common.DC, id);
            count = this.roomRepository.count(ParamHelper.getParams(map, Sign.EQ));
            if (count > 0) {
                logger.warn("Remove fail：have rooms");
                return new BocloudResult<>(false, "删除失败：该数据中心下存在机房，无法删除", "", "");
            }
            boolean result = this.dataCenterRepository.remove(id, userId);
            if (result) {
                return new BocloudResult<>(true, "删除成功");
            }
            logger.info("Data center has been deleted!");
            return new BocloudResult<>(true, "已被删除");
        } catch (Exception e) {
            logger.error("Remove data center fail:", e);
            return new BocloudResult<>(false, "删除失败", null, null);
        }
    }

    @Override
    public BocloudResult basic(Long id) {
        DataCenter bean = null;
        try {
            bean = this.dataCenterRepository.getDCBean(id);
            Assert.notNull(bean, "该数据中心不存在");
        } catch (Exception e) {
            logger.error("Query data center fail:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
        return new BocloudResult<>(true, bean, "查询成功");
    }

    @Override
    public BocloudResult<GridBean<DataCenter>> list(Pager pager, RequestContext context) {

        List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
        Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
        Boolean simple = Optional.ofNullable(pager.getSimple()).orElse(false);
        sorter.put("gmtCreate", Common.ONE);
        Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
        Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
        List<DataCenter> list = null;
        List<SimpleBean> beans = null;
        int total = 0;
        GridBean gridBean = null;
        try {
            total = this.dataCenterRepository.count(params);
            if (simple) {
                beans = this.dataCenterRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = this.dataCenterRepository.list(page, rows, params, sorter);
                for (DataCenter center : list) {
                    if (!StringUtils.isEmpty(center.getProps())) {
                        center.setZoneName(dictionaryRepository.getNameByValue(center.getProps()));
                        Integer vmCount = 0;
                        Integer pmCount = 0;
                        Integer dsCount = 0;
                        // 查询数据中心下云平台
                        List<CloudVendor> vendors = cloudVendorRepository.listByDcId(center.getId());
                        for (CloudVendor vendor : vendors) {
                            List<Param> paramList = new ArrayList<>();
                            paramList.add(new Param(MapTools.simpleMap("vendorId", vendor.getId()), Sign.EQ));
                            vmCount += cloudServerRepository.count(vendor.getId(), 0L);
                            pmCount += serverRepository.countByLabel(paramList, "");
                            dsCount += storeRepository.count(paramList);
                        }
                        center.setVmCount(vmCount);
                        center.setPmCount(pmCount);
                        center.setDsCount(dsCount);
                    }
                }
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query data center list fail:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }


    @Override
    public BocloudResult<DataCenter> detail(Long id) {
        DataCenter center = null;
        try {
            if (id == 0) {
                center = new DataCenter();
                center.setCenters(this.dataCenterRepository.count(null));
                center.setRooms(this.roomRepository.count(null));
                center.setRacks(this.rackRepository.count(null));
                center.setServers(this.serverRepository.countByLabel(new ArrayList<>(), ""));
            } else {
                center = this.dataCenterRepository.getDCBean(id);
                Assert.notNull(center, "该数据中心不存在");
                Map<String, Object> dcMap = new HashMap<String, Object>();
                dcMap.put(Common.DC, id);
                List<Room> roomList = this.roomRepository.list(1, Integer.MAX_VALUE,
                        ParamHelper.getParams(dcMap, Sign.EQ), null);
                List<Rack> rackList = new ArrayList<Rack>();
                int racks = 0;
                int servers = 0;
                if (null != roomList && !roomList.isEmpty()) {
                    Map<String, Object> roomMap = new HashMap<String, Object>();
                    for (Room room : roomList) {
                        roomMap.put(Common.ROOM, room.getId());
                        racks = racks + this.rackRepository.count(ParamHelper.getParams(roomMap, Sign.EQ));
                        rackList = this.rackRepository.list(1, Integer.MAX_VALUE,
                                ParamHelper.getParams(roomMap, Sign.EQ), null);
                        if (null != rackList && !rackList.isEmpty()) {
                            Map<String, Object> rackMap = new HashMap<String, Object>();
                            for (Rack rack : rackList) {
                                rackMap.put(Common.RACK, rack.getId());
                                servers = servers + this.serverRepository.countByLabel(ParamHelper.getParams(rackMap, Sign.EQ), "");
                            }
                        }
                    }
                }
                dcMap.put(Common.DC, id);
                center.setRooms(this.roomRepository.count(ParamHelper.getParams(dcMap, Sign.EQ)));
                center.setRacks(racks);
                center.setServers(servers);
                if (!StringUtils.isEmpty(center.getProps())) {
                    center.setZoneName(dictionaryRepository.getNameByValue(center.getProps()));
                }
                Integer vmCount = 0;
                Integer pmCount = 0;
                Integer dsCount = 0;
                // 查询数据中心下云平台
                List<CloudVendor> vendors = cloudVendorRepository.listByDcId(center.getId());
                for (CloudVendor vendor : vendors) {
                    List<Param> paramList = new ArrayList<>();
                    paramList.add(new Param(MapTools.simpleMap("vendorId", vendor.getId()), Sign.EQ));
                    vmCount += cloudServerRepository.count(vendor.getId(), 0L);
                    pmCount += serverRepository.countByLabel(paramList, "");
                    dsCount += storeRepository.count(paramList);
                }
                center.setVmCount(vmCount);
                center.setPmCount(pmCount);
                center.setDsCount(dsCount);
            }
        } catch (Exception e) {
            logger.error("Query data center detail fail:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
        return new BocloudResult<>(true, center, "查询成功");
    }

	@Override
	public BocloudResult resourceCount(Long dcId) {
		JSONObject resourceObject = new JSONObject();
		int vmNum = 0;
		int hostNum = 0;
		int imageNum = 0;
		try {
			List<CloudVendor> cloudVendors = cloudVendorRepository.listByDcId(dcId);
			if (!ListTool.isEmpty(cloudVendors)) {
				List<Long> vendorIds = cloudVendors.stream().map(CloudVendor::getId).collect(Collectors.toList());
				List<Param> params = new ArrayList<>();
				params.add(new Param(MapTools.simpleMap("vendor_id", this.generateIds(vendorIds)), Sign.IN));
				vmNum = cloudServerRepository.count(params);
				hostNum = serverRepository.count(params, null);
				imageNum = imageRepository.count(params);
			}
			resourceObject.put("vmNum", vmNum);
			resourceObject.put("hostNum", hostNum);
			resourceObject.put("imageNum", imageNum);
			return new BocloudResult<>(true, resourceObject, "查询成功");
		} catch (Exception e) {
			logger.error("根据数据中心统计云主机、主机、镜像异常:", e);
			return new BocloudResult<>(false, "查询失败：" + e.getMessage());
		}
	}
	
	private Object generateIds(List<Long> hostIds) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < hostIds.size(); i++) {
            builder.append(hostIds.get(i)).append(",");
        }
        builder.append(" -1 ");
        return builder.toString();
    }

}