package com.bocloud.ims.service.resource.azure.network;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.azure.network.RouterTableDriver;
import com.bocloud.cmp.driver.network.SubnetDriver;
import com.bocloud.cmp.model.SubnetModel;
import com.bocloud.cmp.model.azure.network.RouterTableModel;
import com.bocloud.cmp.params.azure.AzureRouterTableOperationParams;
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.ResultTools;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.ResourceGroup;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Vpc;
import com.bocloud.ims.entity.resource.azure.account.BatchAccount;
import com.bocloud.ims.entity.resource.azure.network.RouterTable;
import com.bocloud.ims.interfaces.resource.azure.network.RouterTableService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ResourceGroupRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VpcRepository;
import com.bocloud.ims.repository.resource.azure.network.RouterTableRepository;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;
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;

/**
 * @Company: 博云 www.bocloud.com
 * @ClassName: RouterTableServiceImpl
 * @Description:
 * @author: zhenpingLi/李振平
 * @date: 2021/1/5 10:12
 */
@Service("routerTableService")
public class RouterTableServiceImpl implements RouterTableService {

    private static Logger logger = LoggerFactory.getLogger(RouterTableServiceImpl.class);
    @Autowired
    private CloudVendorRepository vendorRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private ResourceGroupRepository resourceGroupRepository;
    @Autowired
    private RouterTableRepository routerTableRepository;
    @Autowired
    private RouterTableDriver routerTableDriver;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private SubnetDriver subnetDriver;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private SmsProjectService socProjectService;


    public BocloudResult unbindSubnet(Long id, RequestContext context) {
        try {
            RouterTable routerTable = routerTableRepository.query(id);
            Assert.notNull(routerTable, "资源不存在");
            ResourceGroup resourceGroup = resourceGroupRepository.query(routerTable.getResourceGroupId());
            Assert.notNull(resourceGroup, "资源组不存在");
            List<Vpc> vpcs = vpcRepository.listByRsg(routerTable.getVendorId(), routerTable.getRegionId(), context.getTenant(), resourceGroup.getName());
            List<Subnet> collect = new ArrayList<>();
            for (Vpc vpc : vpcs) {
                List<Subnet> subnets = subnetRepository.listByNetwork(vpc.getId());
                collect = subnets.stream().filter(subnet -> subnet.getRouterTableId() == null).collect(Collectors.toList());
            }
            return new BocloudResult<>(true, collect, "查询成功");
        } catch (Exception e) {
            logger.error("query subnet error!", e);
            return new BocloudResult<>(false, "查询失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> operation(AzureRouterTableOperationParams params, RequestContext context) {
        if (null != params) {
            String action = params.getAction();
            Long id = params.getId();
            switch (action) {
                case "associateSubnet":
                    return this.associateSubnet(id, params, context);
                case "releaseSubnet":
                    return this.releaseSubnet(id, params, context);
                default:
                    return ResultTools.formatErrResult();
            }
        }
        return ResultTools.formatErrResult();
    }

    public BocloudResult<Void> associateSubnet(Long id, AzureRouterTableOperationParams params, RequestContext context) {
        Long subnetId = params.getSubnetId();
        try {
            RouterTable routerTable = routerTableRepository.query(id);
            Assert.notNull(routerTable, "资源不存在");
            CloudVendor vendor = vendorRepository.query(routerTable.getVendorId());
            Assert.notNull(vendor, "平台验证失败");
            Subnet subnet = subnetRepository.query(subnetId);
            Assert.notNull(subnet, "子网不存在");
            SubnetModel model = new SubnetModel();
            model.setVpcUuid(subnet.getVpcUuid());
            model.setName(subnet.getName());
            model.setRouterTableUuid(routerTable.getUuid());
            BocloudResult result = subnetDriver.associate(vendor.getUuid(), routerTable.getRegionId(), model);
            if (result.isFailed()) {
                return new BocloudResult<>(false, result.getMessage());
            }
            subnet.setRouterTableId(id);
            subnet.setMenderId(context.getTarget());
            subnet.setGmtModify(new Date());
            subnetRepository.update(subnet);
            return new BocloudResult<>(true, "关联成功");
        } catch (Exception e) {
            logger.error("associate subnet error!", e);
            return new BocloudResult<>(false, "关联失败:" + e.getMessage());
        }
    }

    public BocloudResult<Void> releaseSubnet(Long id, AzureRouterTableOperationParams params, RequestContext context) {
        try {
            Long subnetId = params.getSubnetId();
            Subnet subnet = subnetRepository.query(subnetId);
            Assert.notNull(subnet, "子网不存在");
            CloudVendor vendor = vendorRepository.query(subnet.getVendorId());
            Assert.notNull(vendor, "平台不存在");
            SubnetModel model = new SubnetModel();
            model.setVpcUuid(subnet.getVpcUuid());
            model.setName(subnet.getName());
            BocloudResult result = subnetDriver.release(vendor.getUuid(), subnet.getRegionId(), model);
            if (result.isFailed()) {
                return new BocloudResult<>(false, result.getMessage());
            }
            subnet.setRouterTableId(null);
            subnet.setMenderId(context.getTarget());
            subnet.setGmtModify(new Date());
            subnetRepository.update(subnet);
            return new BocloudResult<>(true, "解绑成功");
        } catch (Exception e) {
            logger.error("release subnet error!", e);
            return new BocloudResult<>(false, "解绑失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> create(RouterTable entityParams, RequestContext context) {
        try {
            CloudVendor vendor = vendorRepository.query(entityParams.getVendorId());
            Assert.notNull(vendor, "平台验证失败");
            if (null != routerTableRepository.getByName(entityParams.getVendorId(), entityParams.getResourceGroupId(), entityParams.getName())) {
                return new BocloudResult<>(false, "名称已存在");
            }
            ResourceGroup resourceGroup = resourceGroupRepository.query(entityParams.getResourceGroupId());
            Assert.notNull(resourceGroup, "资源组不能为空");
            RouterTableModel model = new RouterTableModel();
            BeanUtils.copyProperties(entityParams, model);
            model.setResourceGroupName(resourceGroup.getName());
            BocloudResult result = routerTableDriver.create(vendor.getUuid(), entityParams.getRegionId(), model);
            if (result.isFailed()) {
                return new BocloudResult<>(false, result.getMessage());
            }
            model = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), RouterTableModel.class);
            BeanUtils.copyProperties(model, entityParams);
            entityParams.setCreatorId(context.getTarget());
            entityParams.setGmtCreate(new Date());
            entityParams.setTenantId(context.getTenant());
            entityParams.setProjectId(context.getProject());
            if (context.getCatalog() == RequestContext.Catalog.User) {
                entityParams.setUserId(context.getTarget());
            }
            routerTableRepository.save(entityParams);
            return new BocloudResult<>(true, "创建成功");
        } catch (Exception e) {
            logger.error("create routerTable error!", e);
            return new BocloudResult<>(false, "创建失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult modify(RouterTable modifyEntity, RequestContext context) {
        try {
            RouterTable entity = routerTableRepository.query(modifyEntity.getId());
            Assert.notNull(entity, "资源找不到");
            CloudVendor cloudVendor = vendorRepository.query(entity.getVendorId());
            Assert.notNull(cloudVendor, "平台验证失败");

            RouterTableModel model = new RouterTableModel();
            model.setUuid(entity.getUuid());
            model.setRoutePropagation(modifyEntity.getRoutePropagation());
            BocloudResult result = routerTableDriver.modify(cloudVendor.getUuid(), entity.getRegionId(), model);
            if (result.isFailed()) {
                return result;
            }
            entity.setRoutePropagation(modifyEntity.getRoutePropagation());
            routerTableRepository.update(entity);
            return new BocloudResult<>(true, "修改成功");
        } catch (Exception e) {
            logger.error("RouterTable modify fail:", e);
            return new BocloudResult<>(false, "修改失败 : " + e.getMessage());
        }
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = BatchAccount.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            RouterTable entity = routerTableRepository.query(id);
            Assert.notNull(entity, "资源不存在");
            CloudVendor vendor = vendorRepository.query(entity.getVendorId());
            Assert.notNull(vendor, "平台不存在");
            BocloudResult result = routerTableDriver.remove(vendor.getUuid(), entity.getRegionId(), entity.getUuid());
            if (result.isFailed()) {
                return new BocloudResult<>(false, result.getMessage());
            }
            routerTableRepository.remove(id, context.getTarget());
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("remove routerTable error!", e);
            return new BocloudResult<>(false, "删除失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<GridBean<RouterTable>> list(Pager pager, RequestContext context) {
        List<RouterTable> list;
        int total;
        GridBean gridBean;
        List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
        Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
        sorter.put("gmtCreate", Common.ONE);
        Boolean simple = Optional.ofNullable(pager.getSimple()).orElse(false);
        Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
        Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);

        try {
            if (null == params) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            Long tenantId = context.getTenant();
            Long projectId = context.getProject();

            // 为租户下的用户
            if (null != tenantId && 0L != tenantId) {
                List<Project> projects = socProjectService.projectsByCondition(context.getTarget(),
                        context.getCatalog());
                List<Long> projectIds = new ArrayList<>();
                // 此时查询的是全部用户全部项目的信息
                if (null != projectId && 0L != projectId) {
                    projectIds.add(projectId);
                } else if (!ListTool.isEmpty(projects)) {
                    projects.forEach(project -> projectIds.add(project.getId()));
                } else {
                    projectIds.add(-1L);
                }
//                if (context.getCatalog() == RequestContext.Catalog.User) {
//                    total = this.availabilitySetRepository.count(params, null, projectIds, context.getTarget());
//                    list = this.availabilitySetRepository.list(page, rows, params, sorter, null, projectIds, context.getTarget());
//                } else {
                total = this.routerTableRepository.count(params, null, projectIds, null);
                list = this.routerTableRepository.list(page, rows, params, sorter, null, projectIds, null);
//                }
            } else {
                list = routerTableRepository.list(page, rows, params, sorter);
                total = routerTableRepository.count(params);
            }
            gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list routerTable set failure:", e);
            return new BocloudResult<>(false, "查询失败:" + e.getMessage());
        }
    }

    public BocloudResult<RouterTable> detail(Long id, RequestContext context) {
        try {
            RouterTable entity = routerTableRepository.query(id);
            return new BocloudResult<>(true, entity, "查询详情成功");
        } catch (Exception e) {
            logger.error("query routerTable error!", e);
            return new BocloudResult<>(false, "查询详情失败:" + e.getMessage());
        }
    }

    public BocloudResult modify(Long id, String params, RequestContext context) {
        return null;
    }

    @Override
    public BocloudResult<Void> assign(AzureRouterTableOperationParams params, RequestContext context) {
        // 资源ID
        Long id = params.getId();
        // 租户用户ID
        Long userId = params.getUserId();
        // 租户用户所在项目
        Long projectId = params.getProjectId();
        Long tenantId = params.getTenantId();
        try {
            RouterTable entity = routerTableRepository.query(id);
            Assert.notNull(entity, "数据不存在");
            entity.setTenantId(tenantId);
            entity.setProjectId(projectId);
            entity.setUserId(userId);
            routerTableRepository.update(entity);
            logger.info("资源分配操作：success！");
            return new BocloudResult(true, entity, "操作成功");
        } catch (Exception e) {
            logger.error("assign RouterTable  fail:", e);
            return new BocloudResult<>(false, "操作失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> batchAssign(AzureRouterTableOperationParams params, RequestContext context) {
        // 资源ID
        List<Long> ids = params.getIds();
        for (Long id : ids) {
            // 租户用户ID
            Long userId = params.getUserId();
            // 租户用户所在项目
            Long projectId = params.getProjectId();
            Long tenantId = params.getTenantId();
            try {
                RouterTable entity = routerTableRepository.query(id);
                Assert.notNull(entity, "数据不存在");
                entity.setTenantId(tenantId);
                entity.setProjectId(projectId);
                entity.setUserId(userId);
                routerTableRepository.update(entity);
                logger.info("资源分配操作：success！");

            } catch (Exception e) {
                logger.error("assign RouterTable  fail:", e);
                return new BocloudResult<>(false, "操作失败:" + e.getMessage());
            }
        }
        return new BocloudResult<>(true, "操作成功");
    }
}