package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.AuthDriver;
import com.bocloud.cmp.driver.common.EnterpriseDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.EnterpriseProjectModel;
import com.bocloud.cmp.model.OSTenantModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.common.utils.ResultTools;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.OSTenant;
import com.bocloud.ims.entity.resource.PoolGroupZone;
import com.bocloud.ims.entity.resource.Vpc;
import com.bocloud.ims.interfaces.resource.OSTenantService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.OSTenantRepository;
import com.bocloud.ims.repository.resource.PoolGroupRepository;
import com.bocloud.ims.repository.resource.VpcRepository;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;
import com.itextpdf.text.pdf.PdfStructTreeController.returnType;
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.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 底层租户业务实现
 *
 * @author wangyu
 * @version 4.2.1-SNAPSHOT
 * @since 2019/11/14
 */
@Service("oSTenantService")
public class OSTenantServiceImpl implements OSTenantService {

	private static final Logger logger = LoggerFactory.getLogger(OSTenantServiceImpl.class);

	@Autowired
	private OSTenantRepository osTenantRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private AuthDriver authDriver;
	@Autowired
	private SmsTenantService smsTenantService;
	@Autowired
	private PoolGroupRepository poolGroupRepository;
	@Autowired
	private VpcRepository vpcRepository;
	@Autowired
	private NetworkRepository networkRepository;
	@Autowired
	private EnterpriseDriver enterpriseDriver;

	/**
	 * 查询租户列表
	 *
	 * @param pager
	 * @return
	 */
	@Override
	public BocloudResult<GridBean<OSTenant>> list(Pager pager) {
		List<OSTenant> list = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
			sorter.put("gmtCreate", Common.ONE);
			total = osTenantRepository.count(pager.getParams());
			if (pager.getSimple()) {
				List<OSTenant> beans = this.osTenantRepository.list(pager.getParams());
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = this.osTenantRepository.list(pager);
				gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
			}
			return new BocloudResult<>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list  tenant failure:", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	/**
	 * 查询租户详情
	 *
	 * @param id
	 * @return
	 */
	@Override
	public BocloudResult<OSTenant> detail(Long id) {
		try {
			OSTenant oSTenant = this.osTenantRepository.query(id);
			return new BocloudResult<>(true, oSTenant, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult<String> create(OSTenant osTenant, RequestContext context) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			OSTenant oldOsTenant = osTenantRepository.getByName(osTenant.getName(), vendor.getId());
			if (null != oldOsTenant) {
				return new BocloudResult<>(false, "项目名称不允许重复");
			}
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".osTenant";
				String content = "项目创建成功";
				BocloudResult result = null;
				try {
					OSTenantModel osModel = new OSTenantModel();
					osModel.setName(osTenant.getName());
					osModel.setRemark(osTenant.getRemark());
					result = authDriver.createProject(vendor.getUuid(), osModel);
					if (result.isFailed()) {
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
						return;
					}
					osModel = (OSTenantModel) result.getData();
					BeanUtils.copyProperties(osModel, osTenant);
					osTenant.setCreatorId(context.getTarget());
					osTenant.setGmtCreate(new Date());
					osTenant.setVendorId(vendor.getId());
					osTenant.setTenantId(0L);
					osTenantRepository.save(osTenant);
				} catch (Exception e) {
					content = e.getMessage();
					logger.error("创建项目失败：" + e.getMessage());
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<String>(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("create op project error message:", e);
			return new BocloudResult<String>(false, "创建项目:" + e.getMessage());
		}

	}

	@Override
	public BocloudResult<String> remove(Long id, RequestContext context) {
		try {
			OSTenant osTenant = osTenantRepository.query(id);
			Assert.notNull(osTenant, "项目不存在");
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			if (null != osTenant.getTenantId() && osTenant.getTenantId() > 0) {
				return new BocloudResult<>(false, "当前项目已绑定租户，不允许删除");
			}
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".osTenant";
				String content = "项目删除成功";
				BocloudResult result = null;
				try {
					result = authDriver.removeProject(vendor.getUuid(), osTenant.getName());
					if (result.isFailed()) {
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
						return;
					}
					osTenantRepository.remove(id);
				} catch (Exception e) {
					content = e.getMessage();
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<String>(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("create op project error message:", e);
			return new BocloudResult<String>(false, "删除失败:" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<String> modify(OSTenant opTenant, RequestContext context) {
		String path = OSTenant.class.getSimpleName() + "_" + opTenant.getId();
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			OSTenant osTenant = osTenantRepository.query(opTenant.getId());
			Assert.notNull(osTenant, "项目不存在");
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			String newName = opTenant.getName();
			OSTenant oldOsTenant = osTenantRepository.getByName(newName, vendor.getId());
			if (!opTenant.getName().equalsIgnoreCase(osTenant.getName()) && null != oldOsTenant) {
				return new BocloudResult<>(false, "项目名称已存在");
			}
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".osTenant";
				String content = "项目编辑成功";
				BocloudResult result = new BocloudResult<>(true, content);
				try {
					OSTenantModel osModel = new OSTenantModel();
					osModel.setRemark(opTenant.getRemark());
					osModel.setName(opTenant.getName());
					osModel.setTenantUuid(osTenant.getTenantUuid());
					result = authDriver.modifyProject(vendor.getUuid(), osModel);
					if (result.isFailed()) {
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
						return;
					}
					if (CloudProvider.HUAWEI.name().equalsIgnoreCase(vendor.getType())
							|| CloudProvider.HCSO.name().equalsIgnoreCase(vendor.getType())) {
						EnterpriseProjectModel resultModel = (EnterpriseProjectModel) result.getData();
						osTenant.setName(resultModel.getName());
						osTenant.setRemark(resultModel.getRemark());
						osTenant.setUpdateTime(resultModel.getUpdateTime());
						osTenantRepository.update(osTenant);
					} else {
						osModel = (OSTenantModel) result.getData();
						osTenant.setVendorId(vendor.getId());
						osTenant.setName(osModel.getName());
						osTenant.setRemark(osModel.getRemark());
						osTenantRepository.update(osTenant);
					}
				} catch (Exception e) {
					content = e.getMessage();
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<String>(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("create op project error message:", e);
			return new BocloudResult<String>(false, "创建项目:" + e.getMessage());
		}
	}

	@Override
	public BocloudResult assign(OSTenant opTenant, RequestContext context) {
		try {
			OSTenant osTenant = osTenantRepository.query(opTenant.getId());
			Assert.notNull(osTenant, "项目不存在");
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			OSTenant byTenantId = osTenantRepository.getByTenantId(opTenant.getTenantId(), osTenant.getVendorId());
			if (null != byTenantId) {
				return new BocloudResult<>(false, "当前租户已绑定该平台项目");
			}
			osTenant.setTenantId(opTenant.getTenantId());
			osTenantRepository.update(osTenant);
			return new BocloudResult<String>(true, "项目分配成功");
		} catch (Exception e) {
			logger.error("assign op project error message:", e);
			return new BocloudResult<String>(false, "项目分配:" + e.getMessage());
		}

	}

	@Override
	public BocloudResult reclaim(Long id, RequestContext context) {
		try {
			OSTenant osTenant = osTenantRepository.query(id);
			Assert.notNull(osTenant, "项目不存在");
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".osTenant";
				String content = "项目回收成功";
				BocloudResult result = new BocloudResult<>(true, content);
				try {
					BocloudResult checkResult = checkResources(osTenant, vendor, osTenant.getTenantId());
					if (checkResult.isFailed()) {
						resourceEventPublisher.send(new OperateResult(false, checkResult.getMessage(), operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
						return;
					}
					osTenant.setTenantId(0L);
					osTenantRepository.update(osTenant);
				} catch (Exception e) {
					content = e.getMessage();
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<String>(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("assign op project error message:", e);
			return new BocloudResult<String>(false, "项目分配:" + e.getMessage());
		}
	}

	private BocloudResult checkResources(OSTenant osTenant, CloudVendor vendor, Long tenantId) {
		try {
			return new BocloudResult<>(true, "暂无资源");
		} catch (Exception e) {
			logger.error("remove op project check error :", e);
			return new BocloudResult<>(false, "查询租户下资源异常：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult condition(String condition, RequestContext context) {
		condition = Optional.ofNullable(condition).orElse("");
		JSONObject object = JSONObject.parseObject(condition);
		String action = object.getString("condition");
		if ("listTenants".equalsIgnoreCase(action)) {
			return this.listTenants(condition, context);
		}
		if ("listTenantsByUuid".equalsIgnoreCase(action)) {
			return this.listTenantsByUuid(condition, context);
		}
		if ("listTenantsByProject".equalsIgnoreCase(action)) {
			return this.listTenantsByProject(condition, context);
		}
		if ("listBindTenants".equalsIgnoreCase(action)) {
			return this.listBindTenants(condition, context);
		}
		return ResultTools.formatErrResult();
	}

	private BocloudResult listTenantsByUuid(String condition, RequestContext context) {
		try {
			JSONObject object = JSONObject.parseObject(condition);
			String tenantUuid = object.getString("tenantUuid");
			Long vendorId = object.getLong("vendorId");
			List<Tenant> tenants = new ArrayList<>();
			
			OSTenant osTenant = osTenantRepository.getByTenantUuid(tenantUuid, vendorId);
			if (null == osTenant) {
//				List<OSTenant> listBindTenants = osTenantRepository.listBindTenants(vendorId);
//				if (!ListTool.isEmpty(listBindTenants)) {
//					List<Long> collect = listBindTenants.stream().map(OSTenant::getTenantId)
//							.collect(Collectors.toList());
//					tenants.removeIf(tenant -> collect.contains(tenant.getId()));
//				}
				return new BocloudResult<>(false,tenants, "当前资源所属项目未关联平台租户");
			} else {
				BocloudResult<List<Tenant>> bocloudResult = smsTenantService.listAll(new ArrayList<>());
				if (bocloudResult.isFailed()) {
					return bocloudResult;
				}
				tenants = bocloudResult.getData();
				tenants.removeIf(tenant -> !osTenant.getTenantId().equals(tenant.getId()));
			}
			return new BocloudResult<>(true, tenants, "查询成功");
		} catch (Exception e) {
			logger.error("查询项目异常：" + e.getMessage());
			return new BocloudResult<>(false, "查询项目异常：" + e.getMessage());
		}

	}

	/**
	 * 查询项目对应租户关系
	 * 
	 * @param condition
	 * @param context
	 * @return
	 */
	private BocloudResult listTenantsByProject(String condition, RequestContext context) {
		try {
			JSONObject object = JSONObject.parseObject(condition);
			Long vendorId = object.getLong("vendorId");
			BocloudResult<List<Tenant>> bocloudResult = smsTenantService.listAll(new ArrayList<>());
			if (bocloudResult.isFailed()) {
				return bocloudResult;
			}
			List<Tenant> tenants = bocloudResult.getData();
			List<OSTenant> osTenants = osTenantRepository.listByVid(vendorId);
			if (ListTool.isEmpty(osTenants)) {
				return new BocloudResult<>(false, "当前租户列表异常");
			}
			List<Long> tenantIds = osTenants.stream()
					.filter(osTenant -> null != osTenant.getTenantId() && 0 != osTenant.getTenantId())
					.map(OSTenant::getTenantId).collect(Collectors.toList());
			tenants.removeIf(tenant -> tenantIds.contains(tenant.getId()));
			return new BocloudResult<>(true, tenants, "查询成功");
		} catch (Exception e) {
			logger.error("查询项目异常：" + e.getMessage());
			return new BocloudResult<>(false, "查询项目异常：" + e.getMessage());
		}
	}

	private BocloudResult listBindTenants(String condition, RequestContext context) {
		try {
			JSONObject object = JSONObject.parseObject(condition);
			Long networkId = object.getLong("networkId");
			Network network = networkRepository.query(networkId);
			Assert.notNull(network, "网络数据不存在");
			List<Vpc> vpcs = vpcRepository.listByNetworkId(network.getId());
			if (ListTool.isEmpty(vpcs)) {
				return new BocloudResult<>(true, new ArrayList(), "查询成功！");
			}
			BocloudResult<List<Tenant>> bocloudResult = smsTenantService.listAll(new ArrayList<>());
			if (bocloudResult.isFailed()) {
				return bocloudResult;
			}
			List<Long> oldTenantIds = vpcs.stream().map(Vpc::getTenantId).collect(Collectors.toList());
			List<Tenant> tenants = bocloudResult.getData() == null ? new ArrayList<Tenant>() : bocloudResult.getData();
			List<Tenant> tenantList = new ArrayList<>();
			for (Tenant tenant : tenants) {
				if (oldTenantIds.contains(tenant.getId())) {
					tenantList.add(tenant);
				}
			}
			return new BocloudResult<>(true, tenantList, "查询成功！");
		} catch (Exception e) {
			logger.error("查询项目异常：" + e.getMessage());
			return new BocloudResult<>(false, "查询项目异常：" + e.getMessage());
		}

	}

	private BocloudResult listTenants(String condition, RequestContext context) {
		try {
			JSONObject object = JSONObject.parseObject(condition);
			Long networkId = object.getLong("networkId");
			Network network = networkRepository.query(networkId);
			if (null == network) {
				return new BocloudResult<>(false, "网络数据不存在");
			}
			BocloudResult<List<Tenant>> bocloudResult = smsTenantService.listAll(new ArrayList<>());
			if (bocloudResult.isFailed()) {
				return bocloudResult;
			}
			List<Tenant> tenants = bocloudResult.getData();
			Boolean shared = network.getShared() == null ? false : network.getShared();
			Long vendorId = network.getVendorId();
			if (shared) {
				List<Vpc> vpcs = vpcRepository.listByNetworkId(networkId);
				List<Long> oldTenantIds = vpcs.stream().map(Vpc::getTenantId).collect(Collectors.toList());
				if (!ListTool.isEmpty(oldTenantIds)) {
					oldTenantIds.forEach(tenantId -> tenants.removeIf(tenant -> tenantId.equals(tenant.getId())));
				}
			} else {
				String tenantUuid = network.getTenantUuid();
				OSTenant osTenant = osTenantRepository.getByTenantUuid(tenantUuid, vendorId);
				if (null == osTenant) {
					List<OSTenant> listBindTenants = osTenantRepository.listBindTenants(vendorId);
					if (!ListTool.isEmpty(listBindTenants)) {
						List<Long> collect = listBindTenants.stream().map(OSTenant::getTenantId)
								.collect(Collectors.toList());
						tenants.removeIf(tenant -> collect.contains(tenant.getId()));
					}
				} else {
					tenants.removeIf(tenant -> !osTenant.getTenantId().equals(tenant.getId()));
				}
			}
			return new BocloudResult<>(true, tenants, "查询成功");
		} catch (Exception e) {
			logger.error("查询项目异常：" + e.getMessage());
			return new BocloudResult<>(false, "查询项目异常：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult enabled(OSTenant osTenant, RequestContext context) {
		try {
			List<Long> osTenantIds = osTenant.getIds();
			if (ListTool.isEmpty(osTenantIds)) {
				osTenantIds = com.google.api.client.util.Lists.newArrayList();
			}
			OSTenant firstOsTenant = osTenantRepository.query(osTenantIds.get(0));
			Assert.notNull(firstOsTenant, "企业项目不存在");
			CloudVendor vendor = cloudVendorRepository.query(osTenant.getVendorId());
			Assert.notNull(vendor, "云平台不存在!");
			final List<Long> tenantIds = osTenantIds;
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".osTenant";
				String content = "操作成功";
				BocloudResult result = new BocloudResult<>(true, content);
				try {
					EnterpriseProjectModel model = null;
					for (Long osTenantId : tenantIds) {
						OSTenant tenantProject = osTenantRepository.query(osTenantId);
						model = new EnterpriseProjectModel();
						model.setEnabled(osTenant.getEnabled());
						model.setEnterpriseProjectUuid(tenantProject.getTenantUuid());
						BocloudResult modifyEnterpriseProject = enterpriseDriver.enterpriseProjectEnable(vendor.getUuid(), model , null);
						if(modifyEnterpriseProject.isSuccess()) {
							EnterpriseProjectModel resultModel = (EnterpriseProjectModel) modifyEnterpriseProject.getData();
							tenantProject.setEnabled(osTenant.getEnabled());
							tenantProject.setUpdateTime(resultModel.getUpdateTime());
							osTenantRepository.update(tenantProject);
						}
					}
				} catch (Exception e) {
					content = e.getMessage();
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<>(true, "任务已下午，正在执行......");
		} catch (Exception e) {
			logger.error("企业项目状态编辑异常 ：" + e);
			return new BocloudResult<>(false, "企业项目状态编辑异常 ：" + e);
		}
	}
}
