package com.bocloud.ims.service.transportor;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.horizon.VmwareHorizonDesktopPoolModel;
import com.bocloud.cmp.model.horizon.VmwareHorizonFarmModel;
import com.bocloud.cmp.model.horizon.VmwareHorizonSessionModel;
import com.bocloud.cmp.model.horizon.VmwareHorizonSyncModel;
import com.bocloud.cmp.model.horizon.VmwareHorizonUserOrGroupModel;
import com.bocloud.cmp.model.horizon.VmwareHorizonVcenterModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonDesktopPool;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonFarm;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonSession;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonUserOrGroup;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonVcenter;
import com.bocloud.ims.entity.resource.horizon.VmwareHorizonVcenterRelation;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonDesktopPoolRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonFarmRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonSessionRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonUserOrGroupRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonVcenterRelationRepository;
import com.bocloud.ims.repository.resource.horizon.VmwareHorizonVcenterRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * vmware云桌面同步
 * 
 * @author HP
 *
 */
@Slf4j
public class VmwareHorizonTransportor {

	private VmwareHorizonDesktopPoolRepository desktopPoolRepository;
	private VmwareHorizonSessionRepository sessionRepository;
	private VmwareHorizonUserOrGroupRepository userOrGroupRepository;
	private VmwareHorizonVcenterRepository vcenterRepository;
	private VmwareHorizonVcenterRelationRepository vcenterRelationRepository;
	private VmwareHorizonFarmRepository farmRepository;
	private CloudVendorRepository vendorRepository;

	public VmwareHorizonTransportor(VmwareHorizonDesktopPoolRepository desktopPoolRepository,
			VmwareHorizonSessionRepository sessionRepository, VmwareHorizonUserOrGroupRepository userOrGroupRepository,
			VmwareHorizonVcenterRepository vcenterRepository,
			VmwareHorizonVcenterRelationRepository vcenterRelationRepository,
			VmwareHorizonFarmRepository farmRepository, CloudVendorRepository vendorRepository) {
		super();
		this.desktopPoolRepository = desktopPoolRepository;
		this.sessionRepository = sessionRepository;
		this.userOrGroupRepository = userOrGroupRepository;
		this.vcenterRepository = vcenterRepository;
		this.vcenterRelationRepository = vcenterRelationRepository;
		this.farmRepository = farmRepository;
		this.vendorRepository = vendorRepository;
	}

	public BocloudResult sync(CloudVendor vendor, Object data, Long menderId) {
		try {
			if (null != data) {
				Long vendorId = vendor.getId();
				String content = JSONObject.toJSONString(data);
				VmwareHorizonSyncModel model = JSONObject.parseObject(content, VmwareHorizonSyncModel.class);
				Map<String, Long> poolMap = new HashMap<>();
				Map<String, Long> vcenterMap = new HashMap<>();
				Map<String, Long> userOrGroupMap = new HashMap<>();
				// 同步用户，组
				log.info("Starting sync user and group......");
				this.syncUserOrGroup(model.getUserOrGroupModels(), vendorId, menderId, userOrGroupMap);
				log.info("End sync user and group......");
				// 同步场
				log.info("Starting sync farm......");
				this.syncFarm(model.getFarmModels(), vendorId, menderId);
				log.info("End sync farm......");
				// 同步vcenter
				log.info("Starting sync vcenter......");
				this.syncVcenter(model.getVcenterModels(), vendorId, menderId, vcenterMap);
				log.info("End sync vcenter......");
				// 同步horizon-vcenter关系数据
				log.info("Starting sync horizon vcenter relation......");
				this.syncHorizonVcenterRelation(model.getVcenterModels(), vendor.getId());
				log.info("End sync horizon vcenter relation......");
				// 同步桌面池
				log.info("Starting sync desktop pool......");
				this.syncDesktopPool(model.getPoolModels(), vendorId, menderId, vcenterMap, poolMap);
				log.info("End sync desktop pool......");
				// 同步会话
				log.info("Starting sync desktop pool......");
				this.syncSession(model.getSessionModels(), vendorId, menderId, poolMap, userOrGroupMap);
				log.info("End sync desktop pool......");
			}
			return new BocloudResult(true, "VMware Horizon平台【" + vendor.getName() + "】同步成功");
		} catch (Exception e) {
			log.error("Get error message：{}", e);
			return new BocloudResult(false, "同步失败：" + e.getMessage());
		}
	}

	/**
	 * 同步用户，组
	 * 
	 * @param models
	 * @param vendorId
	 * @param menderId
	 * @param newUserOrGroupMap
	 * @throws Exception
	 */
	public void syncUserOrGroup(List<VmwareHorizonUserOrGroupModel> models, Long vendorId, Long menderId,
			Map<String, Long> newUserOrGroupMap) throws Exception {
		if (ListTool.isEmpty(models)) {
			userOrGroupRepository.removeByVendorId(vendorId, menderId);
			return;
		}
		List<VmwareHorizonUserOrGroup> userOrGroups = userOrGroupRepository.listByVendorId(vendorId);
		Map<String, VmwareHorizonUserOrGroup> userOrGroupMap = new HashMap<>();
		for (VmwareHorizonUserOrGroup userOrGroup : userOrGroups) {
			if (userOrGroupMap.containsKey(userOrGroup.getUuid())) {
				userOrGroupRepository.remove(userOrGroup.getId(), menderId);
			} else {
				userOrGroupMap.put(userOrGroup.getUuid(), userOrGroup);
			}
		}
		for (VmwareHorizonUserOrGroupModel model : models) {
			VmwareHorizonUserOrGroup userOrGroup = new VmwareHorizonUserOrGroup();
			if (userOrGroupMap.containsKey(model.getUuid())) {
				userOrGroup = userOrGroupMap.get(model.getUuid());
				BeanUtils.copyProperties(model, userOrGroup);
				userOrGroup.setMenderId(menderId);
				userOrGroup.setGmtModify(new Date());
				userOrGroupRepository.update(userOrGroup);
				newUserOrGroupMap.put(userOrGroup.getUuid(), userOrGroup.getId());
				userOrGroupMap.remove(model.getUuid());
				continue;
			}
			BeanUtils.copyProperties(model, userOrGroup);
			userOrGroup.setCreatorId(menderId);
			userOrGroup.setVendorId(vendorId);
			userOrGroupRepository.save(userOrGroup);
			newUserOrGroupMap.put(userOrGroup.getUuid(), userOrGroup.getId());
			userOrGroupMap.remove(model.getUuid());
		}
		for (Entry<String, VmwareHorizonUserOrGroup> entry : userOrGroupMap.entrySet()) {
			userOrGroupRepository.remove(entry.getValue().getId(), menderId);
		}
	}

	/**
	 * 同步vcenter
	 * 
	 * @param models
	 * @param vendorId
	 * @param menderId
	 * @param newVcenterMap
	 * @throws Exception
	 */
	public void syncVcenter(List<VmwareHorizonVcenterModel> models, Long vendorId, Long menderId,
			Map<String, Long> newVcenterMap) throws Exception {
		if (ListTool.isEmpty(models)) {
			vcenterRepository.removeByVendorId(vendorId, menderId);
			return;
		}
		List<VmwareHorizonVcenter> vcenters = vcenterRepository.listByVendorId(vendorId);
		Map<String, VmwareHorizonVcenter> vcenterMap = new HashMap<>();
		for (VmwareHorizonVcenter vcenter : vcenters) {
			if (vcenterMap.containsKey(vcenter.getUuid())) {
				vcenterRepository.remove(vcenter.getId(), menderId);
			} else {
				vcenterMap.put(vcenter.getUuid(), vcenter);
			}
		}
		for (VmwareHorizonVcenterModel model : models) {
			VmwareHorizonVcenter vcenter = new VmwareHorizonVcenter();
			if (vcenterMap.containsKey(model.getUuid())) {
				vcenter = vcenterMap.get(model.getUuid());
				BeanUtils.copyProperties(model, vcenter);
				vcenter.setMenderId(menderId);
				vcenter.setGmtModify(new Date());
				vcenterRepository.update(vcenter);
				newVcenterMap.put(vcenter.getUuid(), vcenter.getId());
				vcenterMap.remove(model.getUuid());
				continue;
			}
			BeanUtils.copyProperties(model, vcenter);
			vcenter.setCreatorId(menderId);
			vcenter.setVendorId(vendorId);
			vcenterRepository.save(vcenter);
			newVcenterMap.put(vcenter.getUuid(), vcenter.getId());
			vcenterMap.remove(model.getUuid());
		}
		for (Entry<String, VmwareHorizonVcenter> entry : vcenterMap.entrySet()) {
			vcenterRepository.remove(entry.getValue().getId(), menderId);
		}
	}

	/**
	 * 同步horizon-vcenter关系
	 * 
	 * @param models
	 * @param vendorId
	 * @throws Exception
	 */
	public void syncHorizonVcenterRelation(List<VmwareHorizonVcenterModel> models, Long vendorId) throws Exception {
		vcenterRelationRepository.removeByHorizonVendorId(vendorId);
		// 查询所有vcenter云平台
		List<CloudVendor> vcVendors = vendorRepository.listByType(CloudProvider.VMWARE.name());
		for (VmwareHorizonVcenterModel model : models) {
			for (CloudVendor vcVendor : vcVendors) {
				if (!StringUtils.isEmpty(vcVendor.getAuthentication()) && !StringUtils.isEmpty(model.getServerName())
						&& vcVendor.getAuthentication().contains(model.getServerName())) {
					VmwareHorizonVcenterRelation relation = new VmwareHorizonVcenterRelation(null, vendorId,
							vcVendor.getId());
					vcenterRelationRepository.save(relation);
				}
			}
		}
	}

	/**
	 * 同步场
	 * 
	 * @param models
	 * @param vendorId
	 * @param menderId
	 * @throws Exception
	 */
	public void syncFarm(List<VmwareHorizonFarmModel> models, Long vendorId, Long menderId) throws Exception {
		if (ListTool.isEmpty(models)) {
			farmRepository.removeByVendorId(vendorId, menderId);
			return;
		}
		List<VmwareHorizonFarm> farms = farmRepository.listByVendorId(vendorId);
		Map<String, VmwareHorizonFarm> farmMap = new HashMap<>();
		for (VmwareHorizonFarm farm : farms) {
			if (farmMap.containsKey(farm.getUuid())) {
				farmRepository.remove(farm.getId(), menderId);
			} else {
				farmMap.put(farm.getUuid(), farm);
			}
		}
		for (VmwareHorizonFarmModel model : models) {
			VmwareHorizonFarm farm = new VmwareHorizonFarm();
			if (farmMap.containsKey(model.getUuid())) {
				farm = farmMap.get(model.getUuid());
				BeanUtils.copyProperties(model, farm);
				farm.setMenderId(menderId);
				farm.setGmtModify(new Date());
				farmRepository.update(farm);
				farmMap.remove(model.getUuid());
				continue;
			}
			BeanUtils.copyProperties(model, farm);
			farm.setCreatorId(menderId);
			farm.setVendorId(vendorId);
			farmRepository.save(farm);
			farmMap.remove(model.getUuid());
		}
		for (Entry<String, VmwareHorizonFarm> entry : farmMap.entrySet()) {
			farmRepository.remove(entry.getValue().getId(), menderId);
		}
	}

	/**
	 * 同步桌面池
	 * 
	 * @param models
	 * @param vendorId
	 * @param menderId
	 * @param vcenterMap
	 * @param newPoolMap
	 * @throws Exception
	 */
	public void syncDesktopPool(List<VmwareHorizonDesktopPoolModel> models, Long vendorId, Long menderId,
			Map<String, Long> vcenterMap, Map<String, Long> newPoolMap) throws Exception {
		if (ListTool.isEmpty(models)) {
			desktopPoolRepository.removeByVendorId(vendorId, menderId);
			return;
		}
		List<VmwareHorizonDesktopPool> pools = desktopPoolRepository.listByVendorId(vendorId);
		Map<String, VmwareHorizonDesktopPool> poolMap = new HashMap<>();
		for (VmwareHorizonDesktopPool pool : pools) {
			if (poolMap.containsKey(pool.getUuid())) {
				desktopPoolRepository.remove(pool.getId(), menderId);
			} else {
				poolMap.put(pool.getUuid(), pool);
			}
		}
		for (VmwareHorizonDesktopPoolModel model : models) {
			VmwareHorizonDesktopPool pool = new VmwareHorizonDesktopPool();
			if (poolMap.containsKey(model.getUuid())) {
				pool = poolMap.get(model.getUuid());
				BeanUtils.copyProperties(model, pool);
				pool.setMenderId(menderId);
				pool.setGmtModify(new Date());
				pool.setHorizonVcenterId(vcenterMap.get(model.getVcenterId()));
				desktopPoolRepository.update(pool);
				newPoolMap.put(pool.getUuid(), pool.getId());
				poolMap.remove(model.getUuid());
				continue;
			}
			BeanUtils.copyProperties(model, pool);
			pool.setCreatorId(menderId);
			pool.setVendorId(vendorId);
			pool.setHorizonVcenterId(vcenterMap.get(model.getVcenterId()));
			desktopPoolRepository.save(pool);
			newPoolMap.put(pool.getUuid(), pool.getId());
			poolMap.remove(model.getUuid());
		}
		for (Entry<String, VmwareHorizonDesktopPool> entry : poolMap.entrySet()) {
			desktopPoolRepository.remove(entry.getValue().getId(), menderId);
		}
	}

	/**
	 * 同步会话
	 * 
	 * @param models
	 * @param vendorId
	 * @param menderId
	 * @param poolMap
	 * @param userOrGroupMap
	 * @throws Exception
	 */
	public void syncSession(List<VmwareHorizonSessionModel> models, Long vendorId, Long menderId,
			Map<String, Long> poolMap, Map<String, Long> userOrGroupMap) throws Exception {
		if (ListTool.isEmpty(models)) {
			sessionRepository.removeByVendorId(vendorId, menderId);
			return;
		}
		List<VmwareHorizonSession> sessions = sessionRepository.listByVendorId(vendorId);
		Map<String, VmwareHorizonSession> sessionMap = new HashMap<>();
		for (VmwareHorizonSession session : sessions) {
			if (sessionMap.containsKey(session.getUuid())) {
				sessionRepository.remove(session.getId(), menderId);
			} else {
				sessionMap.put(session.getUuid(), session);
			}
		}
		for (VmwareHorizonSessionModel model : models) {
			VmwareHorizonSession session = new VmwareHorizonSession();
			if (sessionMap.containsKey(model.getUuid())) {
				session = sessionMap.get(model.getUuid());
				BeanUtils.copyProperties(model, session);
				session.setMenderId(menderId);
				session.setGmtModify(new Date());
				session.setHorizonUserId(userOrGroupMap.get(model.getUserId()));
				session.setHorizonDesktopPoolId(poolMap.get(model.getDesktopPoolId()));
				sessionRepository.update(session);
				sessionMap.remove(model.getUuid());
				continue;
			}
			BeanUtils.copyProperties(model, session);
			session.setCreatorId(menderId);
			session.setVendorId(vendorId);
			session.setHorizonUserId(userOrGroupMap.get(model.getUserId()));
			session.setHorizonDesktopPoolId(poolMap.get(model.getDesktopPoolId()));
			sessionRepository.save(session);
			sessionMap.remove(model.getUuid());
		}
		for (Entry<String, VmwareHorizonSession> entry : sessionMap.entrySet()) {
			sessionRepository.remove(entry.getValue().getId(), menderId);
		}
	}
}
