package com.bocloud.ims.service.resource;

import com.bocloud.cmp.driver.network.RouteTableAssociationDriver;
import com.bocloud.cmp.driver.network.RouteTableDriver;
import com.bocloud.cmp.driver.network.SubnetDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.RouteTableAssociationService;
import com.bocloud.ims.repository.resource.*;
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service("routeTableAssociationService")
public class RouteTableAssociationServiceImpl implements RouteTableAssociationService {
    private static Logger logger = LoggerFactory.getLogger(RouteTableAssociationServiceImpl.class);
    @Autowired
    private RouteTableAssociationRepository associationRepository;
    @Autowired
    private RouteTableRepository routeTableRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private InternetGatewayRepository gatewayRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private RouteTableAssociationDriver associationDriver;
    @Autowired
    private RouteTableDriver routeTableDriver;
    @Autowired
    private SubnetDriver subnetDriver;

    @Override
    public BocloudResult 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();
            Long vendorId = null;
            Long routeTableId = null;
            for (Param param : params) {
                if (param.getParam().keySet().contains("vendorId")) {
                    vendorId = Long.valueOf(param.getParam().get("vendorId").toString());
                }
                if (param.getParam().keySet().contains("routeTableId")) {
                    routeTableId = Long.valueOf(param.getParam().get("routeTableId").toString());
                }
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (null != vendor && CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                return aliyunList(page, rows, params, sorter, routeTableId);
            }
            params = Optional.ofNullable(params).orElse(new ArrayList<>());
            sorter = Optional.ofNullable(sorter).orElse(Maps.newHashMap());
            sorter.put("gmtCreate", Common.ONE);
            int total = associationRepository.count(params);
            List<RouteTableAssociation> list = associationRepository.list(page, rows, params, sorter);
            GridBean gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list Route Table Associations failure:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    private BocloudResult<GridBean<Subnet>> aliyunList(int page, int rows, List<Param> params, Map<String, String> sorter, Long routeTableId) {
        try {
            if (null == routeTableId) {
                return new BocloudResult<>(false, "路由表id不能为空");
            }
            RouteTable routeTable = routeTableRepository.query(routeTableId);
            if (null == routeTable) {
                return new BocloudResult<>(false, "路由表不存在");
            }
            for (Param param : params) {
                if (param.getParam().keySet().contains("routeTableId")) {
                    param.getParam().put("routeTableId", routeTable.getUuid());
                }
                if (param.getParam().keySet().contains("subnetUuid")) {
                    param.getParam().remove("subnetUuid");
                }
            }

            params = Optional.ofNullable(params).orElse(new ArrayList<>());
            sorter = Optional.ofNullable(sorter).orElse(Maps.newHashMap());
            sorter.put("gmtCreate", Common.ONE);
            int total = subnetRepository.count(params, null);
            List<Subnet> list = subnetRepository.list(page, rows, params, sorter);
            GridBean gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list Route Table Associations failure:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }


    @Override
    public BocloudResult<String> replace(RouteTableAssociation association, RequestContext context) {
        try {
            RouteTable routeTable = routeTableRepository.query(association.getRouteTableId());
            if (null == routeTable) {
                return new BocloudResult<>(false, "RouteTable不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(routeTable.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "指定的地域下云平台不存在");
            }

            Long id = association.getId();

            if (id != null) {
                association = associationRepository.query(id);
            } else {
                // 设置主路由表
                association = associationRepository.queryByMain(routeTable.getVpcId(), vendor.getId(),
                        routeTable.getRegionId());
            }
            if (null == association) {
                return new BocloudResult<>(false, "RouteTableAssociation不存在");
            }

            BocloudResult result = associationDriver.replaceAssociation(routeTable.getUuid(), association.getUuid(),
                    vendor.getUuid(), routeTable.getRegionId());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "关联失败:" + result.getMessage());
            }
            associationRepository.remove(association.getId(), context.getTarget());
            String subnetUuid = association.getSubnetUuid();
            String gatewayUuid = association.getGatewayUuid();
            association = new RouteTableAssociation();
            association.setUuid(String.valueOf(result.getData()));
            if (id == null) {
                association.setMain(true);
            }
            if (StringUtils.isEmpty(subnetUuid)) {
                association.setGatewayUuid(gatewayUuid);
            } else {
                association.setSubnetUuid(subnetUuid);
            }
            association.setRouteTableId(routeTable.getId());
            association.setRouteTableUuid(routeTable.getUuid());
            association.setVendorId(vendor.getId());
            association.setAssociationState("associated");
            association.setVendorId(vendor.getId());
            association.setCreatorId(context.getTarget());
            association.setRegionId(routeTable.getRegionId());
            associationRepository.save(association);
            return new BocloudResult<>(true, "关联成功");
        } catch (Exception e) {
            logger.error("associate route table failure:", e);
            return new BocloudResult<>(false, "关联失败");
        }
    }

    @Override
    public BocloudResult<String> associate(RouteTableAssociation association, RequestContext context) {
        try {
            RouteTable routeTable = routeTableRepository.query(association.getRouteTableId());
            if (null == routeTable) {
                return new BocloudResult<>(false, "RouteTable不存在");
            }

            CloudVendor vendor = cloudVendorRepository.query(routeTable.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "指定的地域下云平台不存在");
            }
            //阿里云
            if (CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                return aliyunAssociate(association, routeTable, vendor);
            }

            InternetGateway gateway = gatewayRepository.query(association.getGatewayId());
            Subnet subnet = subnetRepository.query(association.getSubnetId());

            if (!((null != gateway && null == subnet) || (null != subnet && null == gateway))) {
                return new BocloudResult<>(false, "GateWay或Subnet不存在，且两者不能同时传参");
            }

            BocloudResult result = gateway != null
                    ? associationDriver.associateRouteTable(routeTable.getUuid(), gateway.getInternetGatewayUuid(),
                    null, vendor.getUuid(), routeTable.getRegionId())
                    : associationDriver.associateRouteTable(routeTable.getUuid(), null, subnet.getSubnetUuid(),
                    vendor.getUuid(), routeTable.getRegionId());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "关联失败:" + result.getMessage());
            }
            association = new RouteTableAssociation();
            association.setUuid(String.valueOf(result.getData()));
            association.setMain(false);
            association.setRouteTableId(routeTable.getId());
            association.setRouteTableUuid(routeTable.getUuid());
            association.setVendorId(vendor.getId());
            association.setAssociationState("associated");
            if (gateway != null) {
                association.setGatewayUuid(gateway.getInternetGatewayUuid());
            } else {
                association.setSubnetUuid(subnet.getSubnetUuid());
            }
            association.setCreatorId(context.getTarget());
            association.setRegionId(routeTable.getRegionId());
            associationRepository.save(association);
            if (gateway != null) {
                return new BocloudResult<>(true, "关联网关[" + gateway.getInternetGatewayUuid() + "]成功");
            }
            return new BocloudResult<>(true, "关联子网[" + subnet.getSubnetUuid() + "]成功");
        } catch (Exception e) {
            logger.error("associate route table failure:", e);
            return new BocloudResult<>(false, "关联失败");
        }
    }

    @Override
    public BocloudResult<String> disassociate(RouteTableAssociation association, RequestContext context) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(association.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "指定的地域下云平台不存在");
            }
            //阿里云
            if (CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                return aliyunDisassociate(association);
            }

            association = associationRepository.query(association.getId());
            if (association == null) {
                return new BocloudResult<>(false, "路由关联不存在");
            }
            BocloudResult result = associationDriver.disassociateRouteTable(association.getUuid(), vendor.getUuid(),
                    association.getRegionId());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "取消关联子网[" + association.getSubnetUuid() + "]失败:" + result.getMessage());
            }
            associationRepository.remove(association.getId(), context.getTarget());
            return new BocloudResult<>(true, "取消关联[" + association.getSubnetUuid() + "]成功");
        } catch (Exception e) {
            logger.error("disassociate route table failure:", e);
            return new BocloudResult<>(false, "取消关联失败");
        }
    }

    /**
     * 阿里云子网绑定
     *
     * @param routeTable
     * @param vendor
     * @return
     */
    private BocloudResult aliyunAssociate(RouteTableAssociation association, RouteTable routeTable, CloudVendor vendor) {
        try {
            Subnet subnet = subnetRepository.query(association.getSubnetId());
            if (null == subnet) {
                return new BocloudResult<>(false, "Subnet不存在");
            }

            BocloudResult result = routeTableDriver.associate(vendor.getUuid(), routeTable.getRegionId(), routeTable.getUuid(), subnet.getSubnetUuid());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "关联失败:" + result.getMessage());
            }
            //更新子网路由表信息
            subnet.setRouteTableId(routeTable.getUuid());
            subnetRepository.update(subnet);
            return new BocloudResult<>(true, "关联子网[" + subnet.getSubnetUuid() + "]成功");

        } catch (Exception e) {
            logger.error("associate route table failure:", e);
            return new BocloudResult<>(false, "关联失败");
        }
    }

    /**
     * 阿里云子网解绑
     *
     * @return
     */
    private BocloudResult aliyunDisassociate(RouteTableAssociation association) {
        try {
            RouteTable routeTable = routeTableRepository.query(association.getRouteTableId());
            if (null == routeTable) {
                return new BocloudResult<>(false, "RouteTable不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(routeTable.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "指定的地域下云平台不存在");
            }
            //阿里云
            if (!CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                return new BocloudResult<>(false, "指定的地域下云平台类型错误(需要阿里云)");
            }

            Subnet subnet = subnetRepository.query(association.getSubnetId());
            if (null == subnet || !routeTable.getUuid().equals(subnet.getRouteTableId())) {
                return new BocloudResult<>(false, "路由关联不存在");
            }

            BocloudResult result = routeTableDriver.unAssociate(vendor.getUuid(), subnet.getRegionId(), subnet.getRouteTableId(),
                    subnet.getSubnetUuid());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "取消关联子网[" + subnet.getSubnetUuid() + "]失败:" + result.getMessage());
            }

            //更新子网路由表信息
            //查询vpc下的系统路由表
            RouteTable systemRouteTable = routeTableRepository.query(vendor.getId(), subnet.getRegionId(), subnet.getVpcUuid(), "System");
            if (null != systemRouteTable) {
                subnet.setRouteTableId(systemRouteTable.getUuid());
                subnetRepository.update(subnet);
            }

            return new BocloudResult<>(true, "取消关联[" + subnet.getSubnetUuid() + "]成功");
        } catch (Exception e) {
            logger.error("disassociate route table failure:", e);
            return new BocloudResult<>(false, "取消关联失败");
        }
    }
}
