package com.cf.imes.module.plan.service.orderImport.consumer;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.redis.constants.RedisKeyConstants;
import com.cf.imes.framework.redis.util.RedisLockUtil;
import com.cf.imes.module.executor.enums.OrderImportStatusEnum;
import com.cf.imes.module.executor.enums.OrderImportTaskStatusEnum;
import com.cf.imes.module.plan.dal.dataobject.orderImport.OrderImportTaskDO;
import com.cf.imes.module.plan.dal.mysql.orderImport.OrderImportTaskMapper;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

import jakarta.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.ORDER_IMPORT_DEAD_LETTER_QUEUE;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_PEEK_NOT_EXIST_ERROR;

/**
 * 生产单导入死信队列消费
 *
 * @author Gqr
 * @since 2025/2/12 10:48
 */
@Component
@Slf4j
public class OrderImportDeadLetterConsumer {

    @Resource
    private RedisLockUtil redisLockUtil;

    @Resource
    private OrderImportTaskMapper orderImportTaskMapper;

    private static final String TTL_REASON = "expired";
    private static final String ERROR_REASON = "rejected";

    @RabbitListener(queues = ORDER_IMPORT_DEAD_LETTER_QUEUE)
    public void receive(String message,
                        Channel channel,
                        @Header(value = "peek", required = false) String peek,
                        @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                        @Header(value = "x-death", required = false) List<Map<String, Object>> xDeath) throws IOException {
        log.info("====================【生产单导入收到死信消息：{}】====================", message);
        // 手动确认消息
        channel.basicAck(deliveryTag, false);

        if (StringUtils.isEmpty(peek)) {
            throw ServiceExceptionUtil.exception(WEBCAD_ORDER_IMPORT_PEEK_NOT_EXIST_ERROR);
        } else {
            DynamicDataSourceContextHolder.push(peek);
        }

        Long organId = OrganContextHolder.getOrganId();

        String deadLetterReason = getDeadLetterReason(xDeath);
        long taskId = Long.parseLong(message);

        if(TTL_REASON.equals(deadLetterReason)) {
            // 更新状态为消费超时
            orderImportTaskMapper.update(new LambdaUpdateWrapper<OrderImportTaskDO>()
                    .eq(OrderImportTaskDO::getId, taskId)
                    .set(OrderImportTaskDO::getOrganId, organId)
                    .set(OrderImportTaskDO::getStatus, OrderImportTaskStatusEnum.CONSUME_FAIL.getStatus())
            );
        } else if (ERROR_REASON.equals(deadLetterReason)) {
            // 更新状态为消费成功、导入失败
            orderImportTaskMapper.update(new LambdaUpdateWrapper<OrderImportTaskDO>()
                    .eq(OrderImportTaskDO::getId, taskId)
                    .set(OrderImportTaskDO::getOrganId, organId)
                    .set(OrderImportTaskDO::getStatus, OrderImportTaskStatusEnum.CONSUME_SUCCESS.getStatus())
                    .set(OrderImportTaskDO::getImportStatus, OrderImportStatusEnum.IMPORT_FAIL.getStatus()));
        }

        // 导入锁解锁
        if (ObjectUtil.isNotNull(organId)) {
            redisLockUtil.releaseLock(String.format(RedisKeyConstants.ORDER_IMPORT_LOCK_KEY, organId), message);
        }
    }

    /**
     * 获取进入死信队列原因
     *
     * @param xDeath
     * @return
     */
    private String getDeadLetterReason(List<Map<String, Object>> xDeath) {
        if (xDeath == null || xDeath.isEmpty()) {
            return "unknown";
        }
        // 通常取第一个 x-death 记录的原因（最新的）
        Map<String, Object> firstDeath = xDeath.get(0);
        return (String) firstDeath.get("reason");
    }
}
