package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.network.TargetGroupDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.LbTargetGroupModel;
import com.bocloud.cmp.model.LbTargetGroupOperationParam;
import com.bocloud.cmp.model.LbTargetModel;
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.ims.entity.common.Business;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.common.User;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.LbTargetGroupService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.internal.SmsBusinessService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.internal.SmsUserService;
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.stream.Collectors;

@Service("lbTargetGroupService")
public class LbTargetGroupServiceImpl implements LbTargetGroupService {

	private static Logger logger = LoggerFactory.getLogger(LbTargetGroupServiceImpl.class);
	@Autowired
	private LbTargetGroupRepository lbTargetGroupRepository;
	@Autowired
	private LbTargetRepository lbTargetRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private VpcRepository vpcRepository;
	@Autowired
	private TargetGroupDriver targetGroupDriver;
	@Autowired
	private CloudServerRepository cloudServerRepository;
	@Autowired
	private SmsProjectService smsProjectService;
	@Autowired
	private SmsUserService smsUserService;
	@Autowired
	private SmsBusinessService smsBusinessService;
	@Autowired
	private SmsTenantService smsTenantService;

	@Override
	public BocloudResult<GridBean<LbTargetGroup>> list(Pager pager, RequestContext context) {
		try {
			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);
			Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
			Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);

			int total = 0;
			List<LbTargetGroup> list = new ArrayList<>();
			if (context.getCatalog().equals(RequestContext.Catalog.Tenant)) {
				// 租户能看到 1.属于当前租户的资源 2.租户下所有项目的资源
				List<Project> tenantProjects = smsProjectService.listTenantProjects(context.getTenant());
				List<Long> projectIds = tenantProjects.stream().map(Project::getId).collect(Collectors.toList());
				list = this.lbTargetGroupRepository.list(page, rows, null, context.getTenant(), projectIds, params, sorter,
						null);
				total = this.lbTargetGroupRepository.count(null, context.getTenant(), projectIds, params, null);
				list = convertor(list);
			} else if (context.getCatalog().equals(RequestContext.Catalog.User)) {
				// 用户能看到 1.自己申请的资源 2.自己所在的资源可见项目（资源对项目下所有成员可见）下创建的资源 3.自己管理的项目下的资源
				List<Project> userManagerProjects = smsProjectService.listUserManagerProjects(context.getTarget());
				List<Project> visibleProjects = smsProjectService.listUserVisibleProjects(context.getTarget());
				List<Long> projectIds = new ArrayList<>();
				List<Long> userManagerProjectsIds = userManagerProjects.stream().map(Project::getId)
						.collect(Collectors.toList());
				if (!userManagerProjectsIds.isEmpty()) {
					projectIds.addAll(userManagerProjectsIds);
				}
				List<Long> visibleProjectsIds = visibleProjects.stream().map(Project::getId)
						.collect(Collectors.toList());
				if (!visibleProjectsIds.isEmpty()) {
					projectIds.addAll(visibleProjectsIds);
				}
				list = this.lbTargetGroupRepository.list(page, rows, context.getTarget(), null, projectIds, params, sorter,
						null);
				total = this.lbTargetGroupRepository.count(context.getTarget(), null, projectIds, params, null);
				list = convertor(list);
			} else {
				total = lbTargetGroupRepository.count(params);
				list = lbTargetGroupRepository.list(page, rows, params, sorter);
				list = convertor(list);
			}
			GridBean<LbTargetGroup> gridBean = GridHelper.getBean(page, rows, total, list);
			return new BocloudResult<GridBean<LbTargetGroup>>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list target group failure:", e);
			return new BocloudResult<GridBean<LbTargetGroup>>(false, "查询失败", null, null);
		}
	}

	@Override
	public BocloudResult<LbTargetGroup> create(LbTargetGroup lbTargetGroup, RequestContext context) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(lbTargetGroup.getVendorId());
			Assert.notNull(vendor, "云平台不存在");
			Vpc vpc = vpcRepository.query(lbTargetGroup.getVpcId());
			Assert.notNull(vpc, "VPC不存在");
			LbTargetGroupModel model = JSONObject.parseObject(JSON.toJSONString(lbTargetGroup),
					LbTargetGroupModel.class);
			BocloudResult result = targetGroupDriver.create(model, vendor.getUuid(), lbTargetGroup.getRegionId());
			if (result.isFailed()) {
				return new BocloudResult<>(false, "创建失败:" + result.getMessage(), null, null);
			}
			LbTargetGroup targetGroup = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),
					LbTargetGroup.class);
			if (lbTargetGroup.getLoadBalancerUuids() != null) {
				targetGroup.setLoadBalancerUuids(lbTargetGroup.getLoadBalancerUuids());
			}
			targetGroup.setVendorId(vendor.getId());
			targetGroup.setCreatorId(context.getTarget());
			targetGroup.setRegionId(vpc.getRegionId());
			targetGroup.setCatalog(context.getCatalog());
			targetGroup.setTenantId(context.getTenant() == null ? 0 : context.getTenant());
			targetGroup.setProjectId(context.getProject() == null ? 0 : context.getProject());
			targetGroup.setOwnerId(context.getTarget());
			targetGroup.setMenderId(context.getTarget());
			lbTargetGroupRepository.save(targetGroup);
			return new BocloudResult<LbTargetGroup>(true, targetGroup, "创建成功");
		} catch (Exception e) {
			logger.error("create target group failure:", e);
			return new BocloudResult<LbTargetGroup>(false, "创建失败", null, null);
		}
	}

	@Override
	public BocloudResult remove(Long id, RequestContext context) {
		try {
			LbTargetGroup targetGroup = lbTargetGroupRepository.query(id);
			if (targetGroup == null) {
				return new BocloudResult<>(false, "目标群组不存在", null, null);
			}
			CloudVendor vendor = cloudVendorRepository.query(targetGroup.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "指定的地域下云平台不存在");
			}
			LbTargetGroupModel model = new LbTargetGroupModel();
			BeanUtils.copyProperties(targetGroup, model);
			BocloudResult result = targetGroupDriver.remove(targetGroup.getUuid(), vendor.getUuid(),
					targetGroup.getRegionId());
			if (result.isFailed()) {
				return new BocloudResult<>(false, "删除失败:" + result.getMessage(), null, null);
			}
			lbTargetGroupRepository.remove(targetGroup.getId(), context.getTarget());
			return new BocloudResult<>(true, "删除成功");
		} catch (Exception e) {
			logger.error("delete target group failure:", e);
			return new BocloudResult<>(false, "删除失败", null, null);
		}
	}

	@Override
	public BocloudResult<LbTargetGroup> detail(Long id) {
		try {
			LbTargetGroup group = lbTargetGroupRepository.query(id);
			if (null == group) {
				return new BocloudResult<>(false, "目标群组不存在");
			}
			return new BocloudResult<>(true, group, "查询成功");
		} catch (Exception e) {
			logger.error("query load balancer fail:", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult registerTargets(Long id, Map<String, Integer> targetIdPorts, HashSet<Integer> targetIds,
			String action, RequestContext context) {
		try {
			LbTargetGroup lbTargetGroup = lbTargetGroupRepository.query(id);
			Assert.notNull(lbTargetGroup, "TargetGroup不存在");
			CloudVendor vendor = cloudVendorRepository.query(lbTargetGroup.getVendorId());
			Assert.notNull(vendor, "云平台不存在！");
			CloudProvider provider = CloudProvider.valueOf(vendor.getType());
			if ("deregisterTargets".equals(action)) {
				for (Integer targetId : targetIds) {
					LbTarget target = lbTargetRepository.query(Long.valueOf(targetId));
					targetIdPorts = new HashMap<>();
					targetIdPorts.put(target.getUuid(), target.getPort());
				}
			}
			switch (provider) {
			case AWS:
				Map<String, Integer> newMap = new HashMap<>();
				switch (lbTargetGroup.getType()) {
				case "instance":
					for (String targetId : targetIdPorts.keySet()) {
						if (targetId.contains("-")) {
							newMap.put(targetId, targetIdPorts.get(targetId));
						} else if (targetId.contains(".")) {
							// 根据私网IP查找
							CloudServer cloudServer = cloudServerRepository.queryByIp(targetId, vendor.getId(),
									lbTargetGroup.getRegionId());
							if (cloudServer == null) {
								return new BocloudResult<>(false, "无法找到Ip为" + targetId + "的云主机");
							}
							newMap.put(cloudServer.getInstanceId(), targetIdPorts.get(targetId));
						}
					}
					break;
				case "ip":
					for (String targetId : targetIdPorts.keySet()) {
						if (targetId.contains(".")) {
							newMap.put(targetId, targetIdPorts.get(targetId));
						} else {
							logger.warn("Invalid targets (ip):", targetId);
						}
					}
					break;
				}

				BocloudResult bocloudResult = new BocloudResult<>(false, "修改目标失败");

				if ("registerTargets".equals(action)) {
					// 校验是否已注册
					StringJoiner sj = new StringJoiner(System.lineSeparator());
					for (String targetId : newMap.keySet()) {
						LbTarget target = lbTargetRepository.queryRegistered(id, targetId, newMap.get(targetId));
						if (target != null) {
							sj.add(target.getUuid() + " 已经注册到 " + target.getPort() + " 端口");
						}
					}
					if (sj.length() > 0) {
						bocloudResult.setMessage(sj.toString());
						return bocloudResult;
					}

					bocloudResult = targetGroupDriver.registerTargets(lbTargetGroup.getUuid(), newMap, vendor.getUuid(),
							lbTargetGroup.getRegionId());
					if (bocloudResult.isFailed()) {
						return bocloudResult;
					}
					for (LbTargetModel targetModel : (List<LbTargetModel>) bocloudResult.getData()) {
						LbTarget lbTarget = new LbTarget();
						BeanUtils.copyProperties(targetModel, lbTarget);
						lbTarget.setTgId(lbTargetGroup.getId());
						lbTarget.setCreatorId(context.getTarget());
						lbTarget.setVendorId(vendor.getId());
						lbTarget.setRegionId(lbTargetGroup.getRegionId());
						lbTargetRepository.save(lbTarget);
					}
				} else {
					bocloudResult = targetGroupDriver.deregisterTargets(lbTargetGroup.getUuid(), newMap,
							vendor.getUuid(), lbTargetGroup.getRegionId());
					if (bocloudResult.isFailed()) {
						return bocloudResult;
					}
					for (Integer targetId : targetIds) {
						lbTargetRepository.remove(Long.valueOf(targetId), context.getTarget());
					}
				}
				break;
			case HUAWEI:
			case HCSO:
				break;
			case ALIYUN:
				break;
			default:
				break;
			}
			return new BocloudResult<>(true, "修改目标成功");
		} catch (Exception e) {
			logger.error("Get error message：{}", e.getMessage());
			return new BocloudResult<>(false, e.getMessage());
		}
	}

	@Override
	public BocloudResult operations(Long id, LbTargetGroupOperationParam lbTargetGroupOperationParam, RequestContext context) {
		if ("registerTargets".equalsIgnoreCase(lbTargetGroupOperationParam.getAction())) {
			return this.registerTargets(id, JSONObject.parseObject(lbTargetGroupOperationParam.getTargetIdPorts(), HashMap.class),
					null, "registerTargets", context);
		} else if ("deregisterTargets".equalsIgnoreCase(lbTargetGroupOperationParam.getAction())) {
			return this.registerTargets(id, null, JSONObject.parseObject(lbTargetGroupOperationParam.getTargetIds(), HashSet.class),
					"deregisterTargets", context);
		}
		return new BocloudResult<>(false, "无效操作！");
	}

	public List<LbTargetGroup> convertor(List<LbTargetGroup> list) {
		try {
			if (!ListTool.isEmpty(list)) {
				List<Long> tenantIds = new ArrayList<>();
				List<Long> userIds = new ArrayList<>();
				List<Long> businessIds = new ArrayList<>();
				List<Long> projectIds = new ArrayList<>();
				for (LbTargetGroup lbTargetGroup : list) {
					if (lbTargetGroup.getTenantId() != null) {
						tenantIds.add(lbTargetGroup.getTenantId());
					}
					if (lbTargetGroup.getBusinessId() != null) {
						businessIds.add(lbTargetGroup.getBusinessId());
					}
					if (lbTargetGroup.getProjectId() != null) {
						projectIds.add(lbTargetGroup.getProjectId());
					}
					if (lbTargetGroup.getCreatorId() != null) {
						userIds.add(lbTargetGroup.getCreatorId());
					}
					if (lbTargetGroup.getOwnerId() != null) {
						userIds.add(lbTargetGroup.getOwnerId());
					}
					if (lbTargetGroup.getMenderId() != null) {
						userIds.add(lbTargetGroup.getMenderId());
					}
				}
				Map<Long, String> userMap = smsUserService.listUsersByIds(userIds).stream()
						.collect(Collectors.toMap(User::getId, User::getName));
				Map<Long, String> projectMap = smsProjectService.listProjectsByIds(projectIds).stream()
						.collect(Collectors.toMap(Project::getId, Project::getName));
				Map<Long, String> businessMap = smsBusinessService.listBusinesssByIds(businessIds).stream()
						.collect(Collectors.toMap(Business::getId, Business::getName));
				Map<Long, String> tenantMap = smsTenantService.listTenantsByIds(tenantIds).stream()
						.collect(Collectors.toMap(Tenant::getId, Tenant::getName));
				for (LbTargetGroup lbTargetGroup : list) {
					// 设置云主机归属信息
					if (lbTargetGroup.getTenantId() != null) {
						lbTargetGroup.setTenantName(tenantMap.get(lbTargetGroup.getTenantId()));
					}
					if (lbTargetGroup.getBusinessId() != null) {
						lbTargetGroup.setBusinessName(businessMap.get(lbTargetGroup.getBusinessId()));
					}
					if (lbTargetGroup.getProjectId() != null) {
						lbTargetGroup.setProjectName(projectMap.get(lbTargetGroup.getProjectId()));
					}
					if (lbTargetGroup.getCreatorId() != null) {
						lbTargetGroup.setCreatorName(userMap.get(lbTargetGroup.getCreatorId()));
					}
					if (lbTargetGroup.getOwnerId() != null) {
						lbTargetGroup.setOwnerName(userMap.get(lbTargetGroup.getOwnerId()));
					}
					if (lbTargetGroup.getMenderId() != null) {
						lbTargetGroup.setMenderName(userMap.get(lbTargetGroup.getMenderId()));
					}
				}
			}
		} catch (Exception e) {
			logger.error("获取目标群组基本信息异常：" + e.getMessage());
		}
		return list;
	}
}
