package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.storage.VolumeDriver;
import com.bocloud.cmp.model.VolumeTypeModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.VolumeType;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.interfaces.resource.VolumeTypeService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.VolumeTypeRepository;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 云硬盘类型业务实现
 *
 * @author wangyu
 * @version 4.1.0-SNAPSHOT
 * @since 2019/10/17
 */
@Service("volumeTypeService")
public class VolumeTypeServiceImpl implements VolumeTypeService {

    private static final Logger logger = LoggerFactory.getLogger(VolumeTypeServiceImpl.class);
    @Autowired
    private VolumeTypeRepository volumeTypeRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private VolumeDriver volumeDriver;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;

    /**
     * 查询云硬盘类型列表
     *
     * @param pager
     * @return
     */
    @Override
    public BocloudResult<GridBean<VolumeType>> list(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();

            if (null == params) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            int total = volumeTypeRepository.count(params);
            List<VolumeType> list = volumeTypeRepository.list(page, rows, params, sorter);
            GridBean gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list volume type failure:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<List<VolumeType>> listByZone(Long vendorId, String zoneName, Boolean simple) {
        try {
            List<VolumeType> volumeTypes = volumeTypeRepository.listByVendorId(vendorId);
            List<VolumeType> resultTypes = new ArrayList<>();
            for (VolumeType volumeType : volumeTypes) {
                JSONObject extraSpecsObject = JSON.parseObject(volumeType.getExtraSpecs());
                if (Objects.nonNull(extraSpecsObject) && extraSpecsObject.containsKey("HW:availability_zone")) {
                    String availabilityZone = extraSpecsObject.getString("HW:availability_zone");
                    if (availabilityZone.equals(zoneName)) {
                        resultTypes.add(volumeType);
                    }
                }
            }
            return new BocloudResult<>(true, resultTypes, "查询成功");
        } catch (Exception e) {
            logger.error("list volume type by zone failure:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    /**
     * 查看云硬盘类型详情
     *
     * @param id
     * @return
     */
    @Override
    public BocloudResult<VolumeType> detail(Long id) {
        try {
            VolumeType type = volumeTypeRepository.query(id);
            return new BocloudResult<>(true, type, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    /**
     * 创建云硬盘类型
     *
     * @param type
     * @return
     */
    @SuppressWarnings("unchecked")
    @Override
    public BocloudResult<VolumeType> create(VolumeType type) {
        try {
            VolumeTypeModel model = new VolumeTypeModel();
            model.setName(type.getName());
            if (!StringUtils.isEmpty(type.getExtraSpecs())) {
                model.setExtraSpecMap(JSONObject.parseObject(type.getExtraSpecs(), Map.class));
            }
            CloudVendor vendor = cloudVendorRepository.query(type.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "云平台不存在");
            }
            BocloudResult result = volumeDriver.createVolumeType(model, vendor.getUuid());
            if (result.isFailed()) {
                return result;
            }
            model = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), VolumeTypeModel.class);
            type.setName(model.getName());
            type.setVolumeTypeUuid(model.getVolumeTypeUuid());
            if (null != model.getExtraSpecMap() && !model.getExtraSpecMap().isEmpty()) {
                type.setExtraSpecs(JSONObject.toJSONString(model.getExtraSpecMap()));
            }
            volumeTypeRepository.save(type);
            return new BocloudResult<>(true, type, "添加成功");
        } catch (Exception e) {
            logger.error("Create volume type error:", e);
            return new BocloudResult<>(false, "添加失败");
        }
    }

    /**
     * 删除云硬盘类型
     *
     * @param id
     * @return
     */
    @Override
    public BocloudResult remove(Long id) {
        String path = VolumeType.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            VolumeType type = this.volumeTypeRepository.query(id);
            if (null == type) {
                logger.warn("volume type does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(type.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "云平台不存在");
            }
            BocloudResult result = volumeDriver.deleteVolumeType(type.getVolumeTypeUuid(), vendor.getUuid());
            if (result.isFailed()) {
                return result;
            }
            this.volumeTypeRepository.remove(id);
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Remove volume type error:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    /**
     * 批量删除云硬盘类型
     *
     * @param params
     * @param context
     * @return
     */
    @Override
    public BocloudResult batchRemove(List<Long> idArray, RequestContext context) {
        if (ListTool.isEmpty(idArray)) {
            return new BocloudResult<>(false, "没有需要删除的云硬盘类型！");
        }
        try {
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            Long vendorId = null;
            for (Long id : idArray) {
                VolumeType volumeType = volumeTypeRepository.query(id);
                if (null != volumeType) {
                    if (null == vendorId) {
                        vendorId = volumeType.getVendorId();
                    }
                    BocloudResult result = remove(id);
                    if (result.isSuccess()) {
                        succList.add(new BocloudResult<>(true, "【" + volumeType.getName() + "】删除成功"));
                    } else {
                        failList.add(
                                new BocloudResult<>(false, "【" + volumeType.getName() + "】删除失败：" + result.getMessage()));
                    }
                }
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            String operate = vendor.getType().toLowerCase() + ".volumeType";
            // 删除成功的数量
            int success = succList.size();
            // 删除失败的数量
            int fail = failList.size();
            String content = null;
            if (fail == idArray.size()) {
                content = "云硬盘类型批量删除失败，详情如下：\n";
                for (BocloudResult bocloudResult : failList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                resourceEventPublisher
                        .send(new OperateResult(false, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
            } else {
                content = "云硬盘类型批量删除成功【" + success + "】个,失败【" + fail + "】个，详情如下：\n";
                for (BocloudResult bocloudResult : succList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                for (BocloudResult bocloudResult : failList) {
                    content += bocloudResult.getMessage() + "\n";
                }
                resourceEventPublisher
                        .send(new OperateResult(true, content, operate, MapTools.simpleMap("vendorId", vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
            }
        } catch (Exception e) {
            logger.error("batch remove volume fail:", e);
            return new BocloudResult<>(false, "批量删除任务下发失败");
        }
        return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
    }
}
