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

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.f5.F5DataGroupDriver;
import com.bocloud.cmp.model.f5.DataGroupModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.f5.BiDataGroup;
import com.bocloud.ims.entity.resource.f5.BiPartition;
import com.bocloud.ims.interfaces.resource.f5.F5BiDataGroupService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.f5.F5BiDataGroupRepository;
import com.bocloud.ims.repository.resource.f5.F5BiPartitionRepository;
import com.bocloud.ims.service.utils.BigIpHelper;
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.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.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author lyy
 * @version 1.0
 * @date 2020/11/11 15:37
 */
@Service("f5BiDataGroupService")
public class F5BiDataGroupServiceImpl implements F5BiDataGroupService {
    private static final Logger logger = LoggerFactory.getLogger(F5BiDataGroupServiceImpl.class);
    @Autowired
    private F5BiDataGroupRepository f5BiDataGroupRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private F5BiPartitionRepository f5BiPartitionRepository;
    @Autowired
    private F5DataGroupDriver f5DataGroupDriver;

    @Override
    public BocloudResult list(Pager pager) {
        GridBean gridBean = null;
        int page = pager.getPage();
        int rows = pager.getRows();
        List<Param> params = pager.getParams();
        Map<String, String> sorter = pager.getSorter();
        boolean simple = pager.getSimple();
        try {
            if (null == params) {
                params = Lists.newArrayList();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            for (Param param : params) {
                Map<String, Object> dataMap = param.getParam();
                if (dataMap.containsKey("partitionId")) {
                    Long partitionId = Long.valueOf(dataMap.get("partitionId").toString());
                    BiPartition partition = f5BiPartitionRepository.query(partitionId);
                    if (0 == partitionId) {
                        dataMap.remove("partitionId");
                    } else if (!partition.getName().equals(BigIpHelper.EnumHelper.Common.name())) {
                        BiPartition commonPartition = f5BiPartitionRepository.queryByName(BigIpHelper.EnumHelper.Common.name(),
                                partition.getVendorId());
                        dataMap.remove("partitionId");
                        HashMap<String, Object> queryDataMap = Maps.newHashMap();
                        queryDataMap.put("partitionId",
                                new StringBuilder().append(partitionId).append(",").append(commonPartition.getId()));
                        Param paramData = new Param();
                        paramData.setParam(queryDataMap);
                        paramData.setSign(Sign.IN);
                        params.add(paramData);
                    }
                    break;
                }
            }
            int total = this.f5BiDataGroupRepository.count(params);
            if (simple) {
                List<SimpleBean> beans = this.f5BiDataGroupRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                List<BiDataGroup> groups = this.f5BiDataGroupRepository.list(page, rows, params, sorter);
                List<BiDataGroup> dataGroups = groups.stream().map(group -> {
                    List<JSONObject> allow = JSONArray.parseArray(group.getRecords(), JSONObject.class);
                    group.setAllow(allow);
                    return group;
                }).collect(Collectors.toList());
                gridBean = GridHelper.getBean(page, rows, total, dataGroups);
            }
            return new BocloudResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query BiDataGroup list fail:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult create(BiDataGroup biDataGroup, Long userId) {
        String path = BiDataGroup.class.getSimpleName() + "_" + biDataGroup.getName();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            // 云平台id
            Long vendorId = biDataGroup.getVendorId();
            boolean isExists = f5BiDataGroupRepository.existName(biDataGroup.getName(), vendorId, biDataGroup.getPartitionId());
            if (isExists) {
                return new BocloudResult(false, "添加失败：该名称已存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (null == vendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult(false, "云平台不存在!");
            }
            biDataGroup.setCreatorId(userId);
            biDataGroup.setMenderId(userId);
            biDataGroup.setGmtCreate(new Date());
            BiPartition partition = f5BiPartitionRepository.query(biDataGroup.getPartitionId());
            logger.info("create data group start...");
            // 数据转换
            BocloudResult<DataGroupModel> baseResult = convertData(biDataGroup, partition);
            if (baseResult.isFailed()) {
                logger.error(baseResult.getMessage());
                return new BocloudResult(false, null, baseResult.getMessage());
            }
            DataGroupModel model = baseResult.getData();
            BocloudResult bocloudResult = f5DataGroupDriver.create(vendor.getUuid(), model, "internal");
            if (bocloudResult.isSuccess()) {
                f5BiDataGroupRepository.save(biDataGroup);
                return new BocloudResult(true, "添加成功");
            } else {
                logger.error(bocloudResult.getMessage());
                return new BocloudResult(false, null, bocloudResult.getMessage());
            }
        } catch (Exception e) {
            logger.error("create data group error", e);
            return new BocloudResult(false, e.getMessage());
        }
    }

    private BocloudResult<DataGroupModel> convertData(BiDataGroup biDataGroup, BiPartition partition) throws Exception {
        DataGroupModel model = new DataGroupModel();
        model.setName(biDataGroup.getName());
        model.setType(biDataGroup.getType());
        if (null != biDataGroup.getAllow() && 0 < biDataGroup.getAllow().size()) {
            model.setRecords(biDataGroup.getAllow());
            biDataGroup.setRecords(biDataGroup.getAllow().toString());
        } else {
            biDataGroup.setRecords(new ArrayList<>().toString());
            model.setRecords(new ArrayList<>());
        }
        return new BocloudResult<DataGroupModel>(true, model, "");
    }

    @Override
    public BocloudResult modify(BiDataGroup biDataGroup, Long userId) {
        String path = BiDataGroup.class.getSimpleName() + "_" + biDataGroup.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            CloudVendor vendor = cloudVendorRepository.query(biDataGroup.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure");
                return new BocloudResult(false, "云平台不存在，修改失败");
            }
            String version = vendor.getVersion();
            BiDataGroup object = this.f5BiDataGroupRepository.query(biDataGroup.getId());
            if (null == object) {
                logger.warn("data does not exist!");
                return new BocloudResult(false, "数据不存在");
            }
            biDataGroup.setMenderId(userId);
            biDataGroup.setGmtModify(new Date());
            BiPartition partition = f5BiPartitionRepository.query(biDataGroup.getPartitionId());
            logger.info("update data group start...");
            // 数据转换
            BocloudResult<DataGroupModel> baseResult = convertData(biDataGroup, partition);
            if (baseResult.isFailed()) {
                logger.error(baseResult.getMessage());
                return new BocloudResult(false, null, "更新失败：" + baseResult.getMessage());
            }
            DataGroupModel dataGroupModel = baseResult.getData();
            BocloudResult bocloudResult = f5DataGroupDriver.modify(vendor.getUuid(), dataGroupModel, "internal");
            if (bocloudResult.isSuccess()) {
                f5BiDataGroupRepository.update(biDataGroup);
                return new BocloudResult(true, "更新成功");
            } else {
                logger.error(bocloudResult.getMessage());
                return new BocloudResult(false, null, bocloudResult.getMessage());
            }
        } catch (Exception e) {
            logger.error("Modify data group fail:", e);
            return new BocloudResult(false, "修改失败");
        }
    }

    @Override
    public BocloudResult remove(Long id, Long userId) {
        String path = BiDataGroup.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            BiDataGroup biDataGroup = this.f5BiDataGroupRepository.query(id);
            if (null == biDataGroup) {
                return new BocloudResult(false, "请求内容不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(biDataGroup.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult(false, "删除失败!");
            }
            BiPartition partition = f5BiPartitionRepository.query(biDataGroup.getPartitionId());
            logger.info("remove data group start...");
            BocloudResult result = f5DataGroupDriver.remove(vendor.getUuid(),
                    BigIpHelper.partitionCode(partition.getName(), biDataGroup.getName()), "internal");
            if (result.isSuccess()) {
                f5BiDataGroupRepository.remove(id, userId);
                return new BocloudResult(true, "删除成功");
            } else {
                logger.error(result.getMessage());
                return new BocloudResult(false, null, result.getMessage());
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new BocloudResult(false, "删除失败");
        }
    }


    @Override
    public BocloudResult detail(Long id) {
        try {
            BiDataGroup biDataGroup = this.f5BiDataGroupRepository.query(id);
            if (null == biDataGroup) {
                return new BocloudResult(false, "数据不存在");
            }
            List<JSONObject> allow = JSONArray.parseArray(biDataGroup.getRecords(), JSONObject.class);
            biDataGroup.setAllow(allow);
            return new BocloudResult(true, biDataGroup, "查询数据成功");
        } catch (Exception e) {
            logger.error("Get data group error：", e);
            return new BocloudResult(false, "查询详情失败");
        }
    }
}
