package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.LocationDriver;
import com.bocloud.cmp.driver.common.ZoneDriver;
import com.bocloud.cmp.model.RegionModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.ResultTools;
import com.bocloud.ims.entity.common.Dictionary;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.TenantPool;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.PoolGroup;
import com.bocloud.ims.entity.resource.PoolGroupZone;
import com.bocloud.ims.entity.resource.Region;
import com.bocloud.ims.entity.resource.SecurityGroup;
import com.bocloud.ims.entity.resource.Zone;
import com.bocloud.ims.interfaces.resource.RegionService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.internal.SmsDictionaryService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.google.common.collect.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.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 区域Service接口实现(子区域为zone)
 *
 * @author dongkai
 */
@Service("regionService")
public class RegionServiceImpl implements RegionService {

	private static Logger logger = LoggerFactory.getLogger(RegionServiceImpl.class);
	@Autowired
	private RegionRepository regionRepository;
	@Autowired
	private ZoneRepository zoneRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private PoolGroupRepository poolGroupRepository;
	@Autowired
	private SmsProjectService smsProjectService;
	@Autowired
	private SmsTenantService smsTenantService;
	@Autowired
	private ZoneDriver zoneDriver;
	@Autowired
	private PoolGroupZoneRepository poolGroupZoneRepository;
	@Autowired
    protected SmsDictionaryService smsDictionaryService;
	@Autowired
    protected ServerRepository serverRepository;
    @Autowired
    protected CloudServerRepository cloudServerRepository;
    @Autowired
    protected SnapshotRepository snapshotRepository;
    @Autowired
    protected NetworkRepository networkRepository;
    @Autowired
    protected ImageRepository imageRepository;
    @Autowired
    protected NetworkCardRepository networkCardRepository;
    @Autowired
    protected VolumeRepository volumeRepository;
    @Autowired
    protected ResourceRepository resourceRepository;
    @Autowired
    protected RouteTableRepository routeTableRepository;
    @Autowired
    protected SecurityGroupRepository securityGroupRepository;
    @Autowired
    protected SecurityGroupRuleRepository securityGroupRuleRepository;
    @Autowired
    protected ServerSgroupRepository serverSgroupRepository;
    @Autowired
    protected FlavorRepository flavorRepository;
    @Autowired
    protected FloatingIpRepository floatingIpRepository;
    @Autowired
    protected KeypairRepository keypairRepository;
    @Autowired
    protected SubnetRepository subnetRepository;
    @Autowired
    protected RouterRepository routerRepository;
    @Autowired
    protected RouterRepository routeRepository;
    @Autowired
    protected LoadBalancerRepository loadBalancerRepository;
    @Autowired
    protected LbListenerRepository lbListenerRepository;
    @Autowired
    protected LbMemberRepository lbMemberRepository;
    @Autowired
    protected LbPoolRepository lbPoolRepository;
    @Autowired
    protected FirewallRepository firewallRepository;
    @Autowired
    protected VpcRepository vpcRepository;
    @Autowired
    protected ServerKeypairRepository serverKeypairRepository;
    @Autowired
    protected ElasticIpRepository elasticIpRepository;
    @Autowired
    protected NatGatewayRepository natGatewayRepository;
    @Autowired
    protected NatGatewaySnatRuleRepository natGatewaySnatRuleRepository;
    @Autowired
    protected NatGatewayDnatRuleRepository natGatewayDnatRuleRepository;
    @Autowired
    protected CidrBlockRepository cidrBlockRepository;
    @Autowired
    protected InternetGatewayRepository internetGatewayRepository;
    @Autowired
    protected NetworkInterfaceRepository networkInterfaceRepository;
    @Autowired
    protected LocationDriver locationDriver;

	@Override
	public BocloudResult<List<Region>> list(Long vendorId) {
		try {
			List<Region> list = regionRepository.list(vendorId);
			return new BocloudResult<>(true, list, "查询成功!");
		} catch (Exception e) {
			logger.error("list region failure:", e);
			return new BocloudResult<>(false, "查询失败!");
		}
	}

	@Override
	public BocloudResult<List<Zone>> listZone(Long vendorId, String regionId) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			Assert.notNull(vendor, "云平台不存在");
			List<Zone> list = zoneRepository.listByRegionId(regionId, vendorId);
			return new BocloudResult<>(true, list, "查询成功!");
		} catch (Exception e) {
			logger.error("list region failure:", e);
			return new BocloudResult<>(false, "查询失败!");
		}
	}

	@Override
	public BocloudResult<List<PoolGroupZone>> listRegionByGroup(JSONObject params) {
		try {
			if (null == params) {
				return new BocloudResult<>(false, "参数格式错误");
			}
			Long poolGroupId = params.getLong("poolGroupId");
			PoolGroup poolGroup = poolGroupRepository.query(poolGroupId);
			if (null == poolGroup) {
				logger.error("资源池不存在!");
				return new BocloudResult<>(false, "资源池不存在");
			}
			List<PoolGroupZone> poolGroupZones = poolGroupZoneRepository.listByGroupId(poolGroup.getVendorId(),
					poolGroup.getId(), null, null);
			return new BocloudResult<>(true, poolGroupZones, "查询成功!");
		} catch (Exception e) {
			logger.error("list region failure:", e);
			return new BocloudResult<>(false, "查询失败!");
		}
	}

	@Override
	public BocloudResult<List<Region>> listByBusiness(JSONObject params, RequestContext context) {
		try {
			Long vendorId = params.getLong(Common.VENDORID);
			BocloudResult<Project> projResult = smsProjectService.detail(context.getProject());
			if (projResult.isFailed() || null == projResult.getData()) {
				return new BocloudResult<>(false, "当前用户所在项目不存在");
			}
			List<TenantPool> pools = smsTenantService.listPoolByTenant(context.getTenant());
			if (ListTool.isEmpty(pools)) {
				return new BocloudResult<>(false, "未找到任何云平台");
			}
			Map<Long, Region> regionMaps = Maps.newHashMap();
			for (TenantPool pool : pools) {
				List<Region> regions = regionRepository.listByGroup(pool.getPoolGroupId(), vendorId);
				if (null != regions && regions.size() > 0) {
					for (Region region : regions) {
						regionMaps.put(region.getId(), region);
					}
				}
			}
			return new BocloudResult<>(true, new ArrayList<>(regionMaps.values()), "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult condition(String params, RequestContext context) {
		JSONObject object = JSONTools.isJSONObj(params);
		if (null == object) {
			return ResultTools.formatErrResult();
		}
		String condition = object.getString("condition");
		if ("listregionbygroup".equalsIgnoreCase(condition)) {
			return this.listRegionByGroup(object);
		} else if ("listRegionByBusiness".equalsIgnoreCase(condition)) {
			return this.listByBusiness(object, context);
		} else if ("listByTenant".equalsIgnoreCase(condition)) {
			return this.listByTenant(object, context);
		} else {
			return ResultTools.formatErrResult();
		}
	}

	/**
	 * 根据租户的资源池查询公有云的区域 可用区
	 * 
	 * @param object
	 * @param context
	 * @return
	 */
	public BocloudResult<List<Region>> listByTenant(JSONObject object, RequestContext context) {
		try {
			List<TenantPool> pools = smsTenantService.listPoolByTenant(context.getTenant());
			if (ListTool.isEmpty(pools)) {
				return new BocloudResult<>(false, "当前租户未授权资源池！");
			}
			String vendorType = object.getString("vendorType");
			if (StringUtils.isEmpty(vendorType)) {
				return new BocloudResult<>(false, "平台类型参数异常！");
			}
			List<Long> ids = pools.stream().map(TenantPool::getPoolGroupId).collect(Collectors.toList());
			List<PoolGroup> poolGroups = poolGroupRepository.listByIds(ids, vendorType);

			Map<String, Region> regionMap = new HashMap<>();
			for (PoolGroup poolGroup : poolGroups) {
				String region = poolGroup.getRegion();
				String availablitiyZone = poolGroup.getAvailablitiyZone();

				Region reg = null;
				if (regionMap.containsKey(region)) {
					reg = regionMap.get(region);
				} else {
					reg = regionRepository.getByRegionId(region, poolGroup.getVendorId());
				}
				if (null == reg) {
					continue;
				}
				Set<String> zoneIds = reg.getZoneIds();
				if (null == zoneIds) {
					zoneIds = new HashSet<>();
				}
				zoneIds.add(availablitiyZone);
				reg.setZoneIds(zoneIds);
				regionMap.put(region, reg);
			}
			if (regionMap.values().isEmpty()) {
				return new BocloudResult<>(false, "当前租户暂无该服务可用区域！");
			}
			List<Region> regionList = new ArrayList<>();
			// 获取对象 并 去重
			Set<Entry<String, Region>> entrySet = regionMap.entrySet();
			for (Entry<String, Region> entry : entrySet) {
				Region region = entry.getValue();
				Set<String> zoneIds = region.getZoneIds();
				List<Zone> zones = zoneRepository.listByZoneIds(region.getRegionId(), new ArrayList<>(zoneIds),
						region.getVendorId());
				if (!ListTool.isEmpty(zones)) {
					region.setZones(zones);
				}
				regionList.add(region);
			}
			return new BocloudResult<>(true, regionList, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult zones(Long id, Long vendorId, String type) {
		try {
			if (null == type || null == vendorId) {
				return new BocloudResult(false, "参数有误");
			}
			Region region = regionRepository.query(id);
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			Assert.notNull(region, "当前区域数据不存在");
			Assert.notNull(vendor, "云平台数据不存在");
			BocloudResult result = zoneDriver.queryByRegionId(vendor.getUuid(), type, region.getRegionId());
			if (result.isFailed()) {
				logger.error("获取当前区域下可用区信息失败:", result.getMessage());
				return new BocloudResult(false, "获取当前区域下可用区信息失败");
			}
			return new BocloudResult(true, result.getData(), "查询成功");
		} catch (Exception e) {
			logger.error("list zones failure:", e);
			return new BocloudResult(false, "查询失败:" + e.getMessage());
		}
	}
	
	@Override
	public BocloudResult dicToMap(String vendorType) {
		Map<String, String> dicMap = new HashMap<String, String>(8);
        try {
			BocloudResult<List<Dictionary>> dictionarieResult = smsDictionaryService.dictionaries(vendorType + "_REGION");
			if (dictionarieResult.isFailed()) {
			    throw new RuntimeException("查询区域字段异常：" + dictionarieResult.getMessage());
			}
			List<Dictionary> dictionaries = dictionarieResult.getData();
			if (!ListTool.isEmpty(dictionaries)) {
			    for (Dictionary dictionary : dictionaries) {
			        dicMap.put(dictionary.getValue(), dictionary.getName());
			    }
			}
		} catch (Exception e) {
			logger.error("字典获取区域信息异常：" + e);
		}
        return new BocloudResult<>(true, dicMap, "查询成功");
	}

	/**
	 * 删除区域下的资源
	 * @param regionId
	 * @param vendorId
	 * @param userId
	 * @throws Exception
	 */
	@Override
	public void removeResources(String regionId, Long vendorId, Long userId) throws Exception {
        List<CloudServer> cloudServers = cloudServerRepository.listByVendorId(vendorId, regionId);
        if (!ListTool.isEmpty(cloudServers)) {
            for (CloudServer cloudServer : cloudServers) {
                serverKeypairRepository.removeBySid(cloudServer.getId());
                serverSgroupRepository.removeBySid(cloudServer.getId());
                cloudServerRepository.remove(cloudServer.getId(), userId);
            }
        }
        // 删除原有域下的数据 虚拟安全组关系表 虚拟秘钥关系表
        zoneRepository.deleteByRegionId(regionId, vendorId);
        volumeRepository.removeByVid(vendorId, regionId, userId);
        routerRepository.removeByVid(vendorId, regionId, userId);
        networkRepository.removeByVid(vendorId, regionId, userId);
        imageRepository.removeByVid(vendorId, regionId, userId);
        flavorRepository.removeByVid(vendorId, regionId);
        networkCardRepository.removeByVid(vendorId, regionId, userId);
        floatingIpRepository.removeByVid(vendorId, regionId, userId);
        List<SecurityGroup> listSecurityGroups = securityGroupRepository.listByVendorId(vendorId, regionId);
        for (SecurityGroup group : listSecurityGroups) {
            securityGroupRuleRepository.removeBySgId(group.getId(), userId);
        }
        securityGroupRepository.removeByVid(vendorId, regionId, userId);
        keypairRepository.removeByVid(vendorId, regionId, userId);
        snapshotRepository.removeByVid(vendorId, regionId, userId);
        subnetRepository.removeByVid(vendorId, regionId, userId);
        resourceRepository.removeByVid(vendorId, regionId, userId);
        vpcRepository.deleteByVid(vendorId, regionId, userId);
        poolGroupRepository.removeByVid(vendorId, regionId, userId);
        elasticIpRepository.removeByVid(vendorId, userId, regionId);
        routeRepository.removeByVid(vendorId, regionId, userId);
        loadBalancerRepository.removeByVid(vendorId, regionId, userId);
        lbListenerRepository.removeByVid(vendorId, userId, regionId);
        lbPoolRepository.removeByVid(vendorId, userId, regionId);
        lbMemberRepository.removeByVid(vendorId, userId, regionId);
        poolGroupZoneRepository.deleteByVid(vendorId, regionId);
        natGatewayRepository.removeByVid(vendorId, regionId, userId);
        natGatewaySnatRuleRepository.removeByVid(vendorId, regionId, userId);
        natGatewayDnatRuleRepository.removeByVid(vendorId, regionId, userId);
        cidrBlockRepository.removeByVid(vendorId, regionId, userId, null);
        internetGatewayRepository.removeByVid(vendorId, userId, regionId);
        networkInterfaceRepository.removeByVid(vendorId, userId, regionId);

        routeTableRepository.removeByVid(vendorId, regionId, userId);
    }
	
	/**
	 * 同步云平台下的region
	 * @param vendor
	 * @param userId
	 * @param currentRegions
	 * @throws Exception
	 */
	@Override
	public BocloudResult syncRegion(CloudVendor vendor, Long userId, List<String> currentRegions) throws Exception {
        try {
			// 平台当前区域信息
			List<Region> oldRegionList = regionRepository.list(vendor.getId());
			Map<String, Region> regionMap = new HashMap<>(8);
			for (Region oldR : oldRegionList) {
				regionMap.put(oldR.getCode(), oldR);
			}
			// 同步 区域信息
			BocloudResult listRegions = locationDriver.listRegions(vendor.getUuid(), currentRegions.get(0));
			if (listRegions.isFailed()) {
			    throw new Exception(listRegions.getMessage());
			}
			List<RegionModel> regList = JSON.parseArray(JSON.toJSONString(listRegions.getData()), RegionModel.class);
			// 获取字典中区域
			BocloudResult dicResult = dicToMap(vendor.getType().toUpperCase());
			@SuppressWarnings("unchecked")
			Map<String, String> dicToMap = dicResult.isSuccess() ? (HashMap<String, String>) dicResult.getData() : new HashMap<>();
			// 将不需要的区域过滤掉
			for (int i = regList.size() - 1; i >= 0; i--) {
			    RegionModel regionModel = regList.get(i);
			    String code = regionModel.getCode();
			    if (null != dicToMap && dicToMap.containsKey(code)) {
			        regionModel.setName(dicToMap.get(code));
			    }
			    if (!currentRegions.contains(code)) {
			        regList.remove(regionModel);
			    }
			}
			Region reg = null;
			if (!ListTool.isEmpty(regList)) {
			    // 同步区域
			    for (RegionModel regionModel : regList) {
			        if (regionMap.containsKey(regionModel.getCode())) {
			            reg = regionMap.get(regionModel.getCode());
			            regionModel.setGuid(reg.getGuid());
			            BeanUtils.copyProperties(regionModel, reg);
			            reg.setVendorId(vendor.getId());
			            regionRepository.update(reg);
			            regionMap.remove(regionModel.getCode());
			            continue;
			        }
			        reg = new Region();
			        BeanUtils.copyProperties(regionModel, reg);
			        reg.setVendorId(vendor.getId());
			        reg.setGuid(UUID.randomUUID().toString().replaceAll("-", ""));
			        regionRepository.save(reg);
			    }
			    // 删除区域
			    for (Entry<String, Region> entry : regionMap.entrySet()) {
			        Region region = entry.getValue();
			        regionRepository.delete(region.getId());
			        // 删除区域下对应的资源
			        this.removeResources(region.getRegionId(), vendor.getId(), userId);
			    }
			}
			return new BocloudResult<>(true, "区域同步成功");
		} catch (Exception e) {
			logger.error("云平台同步区域数据异常:" + e.getMessage(), e);
			return new BocloudResult<>(false, "云平台同步区域数据异常：" + e);
		}
    }
	
}
