package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.acd.ims.symphony.sync.SyncOrchestrator;
import com.bocloud.cmp.driver.common.TaskMsgDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.SyncType;
import com.bocloud.cmp.model.TaskMsgModel;
import com.bocloud.common.factory.BoCloudBeanFactory;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.Result;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.common.utils.DateUtils;
import com.bocloud.ims.entity.common.VendorSyncRecord;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.VendorTaskMsg;
import com.bocloud.ims.interfaces.resource.SyncService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.TaskMsgRepository;
import com.bocloud.ims.service.transporter.ResourceTransporter;
import com.bocloud.ims.service.transporter.vendor.AwsTransporter;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 同步云平台service接口实现类
 *
 * @author weiwei
 * @since 2017.02.27
 */
@Service("syncService")
public class SyncServiceImpl implements SyncService {

    private static final Logger logger = LoggerFactory.getLogger(SyncServiceImpl.class);
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private TaskMsgDriver taskMsgDriver;
    @Autowired
    private TaskMsgRepository taskMsgRepository;
    @Autowired
    private BoCloudBeanFactory beanFactory;
    @Autowired
    private AwsTransporter awsTransporter;

    @Autowired
    SyncOrchestrator syncOrchestrator;

    @Override
	public BocloudResult sync(Long id, RequestContext context, boolean isAuto) {
		try {
            logger.info("打印context:{}", JSON.toJSONString(context));
			CloudVendor vendor = cloudVendorRepository.query(id);
			Assert.notNull(vendor, "平台数据不存在！");
            String type = vendor.getType();
            if (CloudProvider.JUMPSERVER.name().equals(type)) {
                return new BocloudResult<>(true, "类型为" + type + "的云平台不在当前服务中同步");
            }

			// 启动一个线程
			taskExecutor.execute(() -> {
				Date startTime = new Date();
				String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId();
				String operate = vendor.getType().toLowerCase() + ".sync";
				OperateResult operateResult = new OperateResult(true, "同步成功", operate,
						MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
						context);
				logger.info("开始同步 " + vendor.getName() + " 平台数据......");
				try (BocloudACLock lock = lockFactory.getACLock(path)) {
					Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前平台可能存在同步任务或资源处于申请中.");
					// 版本5.6 HCSO暂时走华为公有云逻辑 6.0回归黄河云
					String vendorType = vendor.getType().toLowerCase();
					if(CloudProvider.HCSO.name().equalsIgnoreCase(vendorType)) {
						vendorType = CloudProvider.HUAWEI.name().toLowerCase();
					}
                    if (CloudProvider.SANGFOR.name().equalsIgnoreCase(vendorType)){
                        if (vendor.getVersion().equals("6.8")){
                            vendorType = vendorType+"V68";
                        }
                    }
                    ResourceTransporter transporter = beanFactory
                            .getBean(vendorType + "Transporter", ResourceTransporter.class);
                    if (null != transporter) {//这里走原来的产品逻辑
                        Assert.notNull(transporter, "平台同步组件不存在！");
                        Result result = transporter.transport(vendor, context.getTarget());
                        logger.info("云平台同步任务结果：{}", result.getMessage());
                        operateResult.setSuccess(result.isSuccess());
                        operateResult.setMessage(result.getMessage());
                    } else {//这里走acd的统一分发同步逻辑
                        syncOrchestrator.syncCloudVendor(vendor.getId(), context);
                        operateResult.setSuccess(true);
                        operateResult.setMessage("平台同步成功");
                    }
				} catch (Exception e) {
					logger.error("当前云平台存在同步任务异常", e);
					operateResult.setSuccess(false);
					operateResult.setMessage("云平台同步失败：" + e.getMessage());
				}
				if (!isAuto) {
					resourceEventPublisher.send(operateResult);
				}
				VendorSyncRecord record = new VendorSyncRecord();
				record.setVendorId(vendor.getId());
				record.setStartTime(startTime);
				record.setEndTime(new Date());
				record.setCost(record.getEndTime().getTime() - startTime.getTime());
				record.setResult(operateResult.getMessage());
				record.setCreatorId(context.getTarget());
				record.setSyncResult(operateResult.isSuccess());
				record.setAuto(isAuto);
				amqpTemplate.convertAndSend("vendor.record.queue", record);
				if (operateResult.isSuccess()) {
					// 发送给云平台统计队列对云平台重新统计
					JSONObject object = new JSONObject();
					object.put(Common.VENDORID, vendor.getId());
					amqpTemplate.convertAndSend("vendor.statistics.queue", object);
				}
				// 更新云平台最后一次同步时间
				vendor.setGmtModify(record.getEndTime());
				vendor.setMenderId(context.getTarget());
				cloudVendorRepository.update(vendor);
			});
			return new BocloudResult<>(true, "同步任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("sync cloudvendor exception ", e);
			return new BocloudResult<>(false, "云平台数据同步失败: " + e.getMessage());
		}
	}

    /**
     * 同步平台指定类型数据
     *
     * @param id
     * @param context
     * @param syncType
     * @return
     */
    @Override
    public BocloudResult sync(Long id, RequestContext context, SyncType syncType) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(id);
            if (null == vendor) {
                logger.error("平台数据不存在!");
                return new BocloudResult<>(false, "平台数据不存在");
            }
            // 启动一个线程
            new Thread(() -> {
                Date startTime = new Date();
                String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId() + "_" + syncType.name();
                String operate = vendor.getType().toLowerCase() + ".sync";
                OperateResult operateResult = new OperateResult(true, "同步成功", operate,
                        MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
                        context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                    logger.info("开始执行云平台{} 的同步操作", vendor.getName());
                    BocloudResult result = new BocloudResult<>(false, "暂不支持");
                    switch (syncType) {
                        case LOAD_BALANCER:
                            result = awsTransporter.syncAwsLB(vendor, context);
                            break;
                        default:
                            break;
                    }
                    logger.info("云平台同步任务结果：{}", result.getMessage());
                    operateResult.setSuccess(result.isSuccess());
                    operateResult.setMessage(result.getMessage());
                } catch (Exception e) {
                    logger.error("当前云平台存在同步任务异常", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage("当前云平台存在同步任务异常");
                }
                resourceEventPublisher.send(operateResult);
                VendorSyncRecord record = new VendorSyncRecord();
                record.setVendorId(vendor.getId());
                record.setStartTime(startTime);
                record.setEndTime(new Date());
                record.setCost(record.getEndTime().getTime() - startTime.getTime());
                record.setResult(operateResult.getMessage());
                record.setCreatorId(context.getTarget());
                record.setSyncResult(operateResult.isSuccess());
                amqpTemplate.convertAndSend("vendor.record.queue", record);
                if (operateResult.isSuccess()) {
                    // 发送给云平台统计队列对云平台重新统计
                    JSONObject object = new JSONObject();
                    object.put(Common.VENDORID, vendor.getId());
                    amqpTemplate.convertAndSend("vendor.statistics.queue", object);
                }
                // 更新云平台最后一次同步时间
                vendor.setGmtModify(record.getEndTime());
                vendor.setMenderId(context.getTarget());
                cloudVendorRepository.update(vendor);
            }).start();
            return new BocloudResult<>(true, "同步任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("sync cloudvendor exception ", e);
            return new BocloudResult<>(false, "同步失败!");
        }
    }

    @Override
    public BocloudResult syncContentVendorTaskMsg(Long vendorId) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(vendor, "云平台不存在");
            BocloudResult<List<TaskMsgModel>> result = taskMsgDriver.historyList(vendor.getUuid());
            if (result.isSuccess() && null != result.getData()) {
                logger.info("Start sync VendorTaskMsg ");
                syncVendorTaskMsg(result.getData(), vendorId);
                logger.info("End sync VendorTaskMsg ");
            }
            if (result.isFailed()) {
                return new BocloudResult(false, "平台历史任务同步失败:" + result.getMessage());
            }
            return new BocloudResult(true, "平台历史任务同步成功");
        } catch (Exception e) {
            logger.error("Get error message:{}", e);
            return new BocloudResult(false, "平台历史任务同步失败:" + e.getMessage());
        }
    }

    @Override
    public void syncVendorTaskMsg(List<TaskMsgModel> models, Long vendorId) {
        if (ListTool.isEmpty(models)) {
            return;
        }

        // 这个地方不能查询所有任务，会造成数据量过大导致内存溢出   sxp:2023.8.26
        // 定时任务每5分钟执行一次，这里获取15分钟之内的数据可以大概率覆盖近期任务
        Date now = DateUtils.getTodayTime();
        Date minQueueTime = DateUtils.addMinute(now, -15);
        List<VendorTaskMsg> vendorTaskMsgOld = taskMsgRepository.queryRecentTask(vendorId, minQueueTime);

        List<VendorTaskMsg> vendorAddTaskList = new ArrayList<>();
        Map<String, VendorTaskMsg> vendorTaskMsgMap = new HashMap<>();
        if (!ListTool.isEmpty(vendorTaskMsgOld)) {
            vendorTaskMsgMap = vendorTaskMsgOld.stream().collect(Collectors.toMap(VendorTaskMsg::getKey, Function.identity(), (key1, key2) -> key2));
        }
        //未执行完成的任务
        Map<String, VendorTaskMsg> runningTaskMsg = vendorTaskMsgOld.stream().filter(vendorTaskMsg -> null == vendorTaskMsg.getCompleteTime()).collect(Collectors.toMap(VendorTaskMsg::getKey, Function.identity(),
                (key1, key2) -> key2));
        boolean hasRunningTask = (runningTaskMsg != null && !runningTaskMsg.isEmpty());

        for (TaskMsgModel taskMsgMode : models) {
            //历史数据不存在
            if (!vendorTaskMsgMap.containsKey(taskMsgMode.getKey())) {
                VendorTaskMsg vendorTaskMsg = new VendorTaskMsg();
                BeanUtils.copyProperties(taskMsgMode, vendorTaskMsg);
                vendorTaskMsg.setVendorId(vendorId);
                vendorAddTaskList.add(vendorTaskMsg);
            }
            //处理未执行完成的任务,设置结束时间及执行时间
            if (hasRunningTask) {
                if (runningTaskMsg.containsKey(taskMsgMode.getKey())) {
                    VendorTaskMsg vendorTaskMsg = runningTaskMsg.get(taskMsgMode.getKey());
                    if (vendorTaskMsg != null) {
                        BeanUtils.copyProperties(taskMsgMode, vendorTaskMsg);
                        taskMsgRepository.update(vendorTaskMsg);
                    }
                }
            }
        }

        if (!ListTool.isEmpty(vendorAddTaskList)) {
            for (VendorTaskMsg taskMsg : vendorAddTaskList) {
                try {
                    taskMsgRepository.save(taskMsg);
                } catch (Exception e) {
                    // 数据库建立唯一索引(task_key,vendor_id),如果存在重复则重复数据无法保存到数据库
                    logger.warn("近期任务保存出错：" + e.getMessage() + "，忽略重复数据");
                }
            }
        }
    }

}
