package net.northking.cctp.executePlan.consumer;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.rabbitmq.client.Channel;
import net.northking.cctp.executePlan.api.service.AtuPlanBatchApiService;
import net.northking.cctp.executePlan.api.service.AtuPlanTaskApiService;
import net.northking.cctp.executePlan.constants.MsgConstant;
import net.northking.cctp.executePlan.constants.PlanConstant;
import net.northking.cctp.executePlan.constants.RabbitConstant;
import net.northking.cctp.executePlan.constants.RedisConstant;
import net.northking.cctp.executePlan.db.entity.AtuPlanTask;
import net.northking.cctp.executePlan.dto.planBatch.AtuBatchCaseInfoDto;
import net.northking.cctp.executePlan.dto.planTask.QuoteData;
import net.northking.cctp.executePlan.feign.PublicFeignClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.Map;

/**
 * <p>Title: CreatedTaskConsumer</p>
 * <p>Description: 用例生成任务并推送至队列</p>
 *
 * @Author chenjianfeng
 * @Version V1.0
 * @Date 2022/12/09
 * <p>Copyright (c) 京北方信息技术股份有限公司 Corporation 2022 . All rights reserved.</p>
 */
@Component
public class CreatedTaskConsumer {

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

    @Autowired
    private AtuPlanTaskApiService atuPlanTaskApiService;

    @Autowired
    private AtuPlanBatchApiService planBatchApiService;

    @Autowired
    private AmqpAdmin amqpAdmin;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private PublicFeignClient publicFeignClient;

    @PostConstruct
    public void init(){
        // 初始化队列并绑定到交换机
        Exchange exchange = new DirectExchange(RabbitConstant.PROJECT_EXCHANGE_KEY);
        amqpAdmin.declareExchange(exchange);
        Queue queue = new Queue(RabbitConstant.PLAN_CASE_KEY);
        amqpAdmin.declareQueue(queue);
        Binding binding = BindingBuilder.bind(queue).to(exchange)
                .with(RabbitConstant.PLAN_CASE_KEY).noargs();
        amqpAdmin.declareBinding(binding);
    }

    /**
     * 计划用例生成任务
     * @param message 对象消息
     */
    @Transactional(rollbackFor = Exception.class)
    @RabbitListener(queues = RabbitConstant.PLAN_CASE_KEY)
    public void receive(Message message, Channel channel) throws Exception{
        try {
            logger.info("计划用例生成任务 ==> " + new String(message.getBody()));
            JSONObject event = JSONUtil.parseObj(new String(message.getBody()));
            AtuBatchCaseInfoDto batchCaseInfo = JSONUtil.toBean(event, AtuBatchCaseInfoDto.class);
            createdTask(batchCaseInfo);
        }catch (Exception e){
            logger.error("任务生成失败", e);
        }
    }


    /**
     * 生成并保存任务信息
     * @param batchCaseInfo 用例信息
     */
    private void createdTask(AtuBatchCaseInfoDto batchCaseInfo){
        AtuPlanTask planTask = new AtuPlanTask();
        BeanUtil.copyProperties(batchCaseInfo, planTask);
        String taskId = StrUtil.isEmpty(batchCaseInfo.getTaskId()) ? IdUtil.simpleUUID() : batchCaseInfo.getTaskId();
        planTask.setId(taskId);
        planTask.setScriptJson(batchCaseInfo.getScriptPath());
        if (CollUtil.isNotEmpty(batchCaseInfo.getCaseParam())) {
            Map<String, Object> paramsMap = atuPlanTaskApiService.handleQuoteData(batchCaseInfo.getCaseParam(),
                    planTask.getEnvId(), batchCaseInfo.getProjectId());
            planTask.setCaseParam(JSONUtil.toJsonStr(paramsMap));
        }
        // 用例名称为引用数据或名称过长处理
        updateCaseName(planTask);

        // 用例编号
        Object resultCode = redisTemplate.opsForValue().get(MsgConstant.UITEST_SCRIPTCODE + batchCaseInfo.getScriptId());
        if (resultCode != null && !resultCode.equals("")) {
            planTask.setCaseNo(resultCode.toString());
        }
        planTask.setCreatedTime(new Date());
        atuPlanTaskApiService.insert(planTask);

        // 增加批次脚本任务缓存
        String scriptTaskKey = RedisConstant.BATCH_SCRIPT_TASK_KEY + planTask.getBatchId() + ":" + planTask.getScriptId();
        String clusterPrefix = RedisConstant.CLUSTER_KEY_PREFIX + planTask.getBatchId().substring(0,4) +
                    RedisConstant.CLUSTER_KEY_SUFFIX;
        redisTemplate.opsForHash().put(clusterPrefix + scriptTaskKey, clusterPrefix + planTask.getId(), planTask.getId());

        // 生成任务执行信息
        // 任务生成异常，结束该任务
        try {
            atuPlanTaskApiService.createTaskExecuteInfo(planTask, batchCaseInfo);
        }catch (Exception e){
            logger.error("生成任务执行信息并推送至队列异常", e);
            atuPlanTaskApiService.taskExecFailUpdate(planTask, PlanConstant.TASK_EXECUTE_FAIL_STATUS,
                    "生成任务执行信息并推送至队列异常，" + e.getMessage());
        }
    }

    private void updateCaseName(AtuPlanTask planTask){
        String data = planTask.getCaseName();
        try {
            QuoteData quoteData = BeanUtil.toBean(data, QuoteData.class);
            quoteData.setEnvId(planTask.getEnvId());
            if (quoteData.getTip() != null) {
                logger.debug("查询引用数据：{}", JSONUtil.toJsonStr(quoteData));
                QuoteData result = publicFeignClient.selectDataUrlAndTreeName(quoteData);
                if (result != null) {
                    logger.debug("引用的数据为：{}", result.getValue());
                    data = result.getValue();
                }
            }
        }catch (Exception e){
            logger.error("获取引用数据失败", e);
        }
        if (data.length() >= 90){
            logger.debug("用例名称过长，截取部分数据 => {}", data);
            data = data.substring(0, 85);
        }
        planTask.setCaseName(data);
    }
}
