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.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.generator.SnowFlakeGenerator;
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.goods.GoodsMapper;
import com.cf.imes.module.plan.dal.mysql.order.OrderMapper;
import com.cf.imes.module.plan.dal.mysql.orderBody.OrderBodyMapper;
import com.cf.imes.module.plan.dal.mysql.orderGroup.OrderGroupMapper;
import com.cf.imes.module.plan.dal.mysql.orderImport.OrderImportTaskMapper;
import com.cf.imes.module.plan.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.plan.dal.mysql.rawgoods.RawGoodsMapper;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.order.OrderInputProcessor;
import com.cf.imes.module.plan.service.orderImport.OrderImportTaskService;
import com.cf.imes.module.plan.service.orderImport.factory.WebCadOrderImportAsyncFactory;
import com.cf.imes.module.plan.service.orderImport.property.WebCadImportProperties;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
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.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.thymeleaf.util.StringUtils;

import jakarta.annotation.Resource;

import static com.cf.imes.module.plan.enums.ErrorCodeConstants.ORDER_IMPORT_FAIL;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.ORDER_IMPORT_ORGANID_NOT_EXISTS;
import static com.cf.imes.module.plan.enums.ErrorCodeConstants.WEBCAD_ORDER_IMPORT_PEEK_NOT_EXIST_ERROR;

/**
 * webcad拆单消费者
 *
 * @author Gqr
 * @since 2025/4/21 13:46
 */
@Component
@Slf4j
public class WebCadOrderImportConsumer {
    @Resource
    private OrderMapper orderMapper;

    @Resource
    private SnowFlakeGenerator snowFlakeGenerator;

    @Resource
    private OrderBodyMapper orderBodyMapper;

    @Resource
    private PlateMapper plateMapper;

    @Resource
    private OrderGroupMapper orderGroupMapper;

    @Resource
    private SnowflakeIdWorker3rd idWorker;

    @Resource
    private OrderInputProcessor orderInputProcessor;

    @Resource
    private CustomPlateNoGenerateService customPlateNoGenerateService;

    @Resource
    private RedisLockUtil redisLockUtil;

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private RawGoodsMapper rawGoodsMapper;

    @Resource
    private SystemConfigApi systemConfigApi;

    @Value("${chenfeng.plan.webcad.import.cadImportPlateNumThreshold:10000}")
    private int cadImportPlateNumThreshold;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Resource
    private OrderImportTaskMapper orderImportTaskMapper;

    @Resource
    private OrderImportTaskService orderImportTaskService;

    @Resource
    private WebCadImportProperties webCadImportProperties;

    @Resource
    private DataSourceTransactionManager transactionManager;

    @RabbitListener(queues = "#{@orderImportWebCadQueueName}")
    public void orderImport(String message,
                            Channel channel,
                            @Header(value = "peek", required = false) String peek,
                            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
        log.info("====================【webcad异步拆单收到消息：{}】====================", message);

        Long organId = null;
        Long taskId = Long.parseLong(message);
        boolean nackSent = false;
        TransactionStatus transactionStatus = null;
        try {
            organId = OrganContextHolder.getOrganId();
            if (ObjectUtil.isNull(organId)) {
                throw ServiceExceptionUtil.exception(ORDER_IMPORT_ORGANID_NOT_EXISTS);
            }

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

            // 获取事务
            transactionStatus = transactionManager.getTransaction(TransactionDefinition.withDefaults());
            // 确认任务，更新状态为消费成功，没有找到任务中断后续消费
            OrderImportTaskDO orderImportTaskDO = confirmOrderImport(taskId, organId);
            if (ObjectUtil.isNull(orderImportTaskDO)) {
                return;
            }
            log.info("====================【webcad异步拆单处理临时数据开始】====================");
            WebCadOrderImportAsyncFactory webCadOrderImportAsyncFactory =
                    new WebCadOrderImportAsyncFactory(organId, orderMapper, snowFlakeGenerator, orderBodyMapper, plateMapper, orderGroupMapper, idWorker,
                            orderImportTaskMapper, orderInputProcessor, goodsMapper, rawGoodsMapper, customPlateNoGenerateService, systemConfigApi, orderImportTaskDO.getCreator(), cadImportPlateNumThreshold, jdbcTemplate);
            webCadOrderImportAsyncFactory.analyzeTempData(taskId, webCadImportProperties.getTempFilePath());
            log.info("====================【webcad异步拆单处理临时数据结束】====================");

            // 提交事务
            transactionManager.commit(transactionStatus);
        } catch (ServiceException se) {
            String seMessage = se.getMessage();
            log.error(seMessage);
            // 回滚事务
            if (transactionStatus != null) {
                transactionManager.rollback(transactionStatus);
            }

            // 更新任务状态
            orderImportTaskService.updateServiceExceptionTaskStatus(taskId, organId, seMessage);

            nackSent = true;
            // 确认消息进入死信队列
            channel.basicNack(deliveryTag, false, false);
        } catch (Exception e) {
            log.error(ORDER_IMPORT_FAIL.getMsg(), e);
            // 回滚事务
            if (transactionStatus != null) {
                transactionManager.rollback(transactionStatus);
            }

            // 更新任务状态
            orderImportTaskService.updateExceptionTaskStatus(taskId, organId);

            nackSent = true;
            // 确认消息进入死信队列
            channel.basicNack(deliveryTag, false, false);
        } finally {
            // 手动确认消息接收
            if (!nackSent) {
                channel.basicAck(deliveryTag, false);
            }
            // 导入锁解锁
            redisLockUtil.releaseLock(String.format(RedisKeyConstants.ORDER_IMPORT_LOCK_KEY, organId), message);
        }
    }

    /**
     * 确认导入任务，更新任务状态
     *
     * @param taskId
     */
    private OrderImportTaskDO confirmOrderImport(Long taskId, Long organId) {
        boolean taskExist = false;
        OrderImportTaskDO orderImportTaskDO = null;
        // 线程每1s查询一次，查三次没有就提示任务不存在
        for (int i = 0; i < 3; i++) {
            orderImportTaskDO = orderImportTaskMapper.selectOne(new LambdaQueryWrapper<OrderImportTaskDO>()
                    .eq(OrderImportTaskDO::getId, taskId)
                    .eq(OrderImportTaskDO::getOrganId, organId));
            if (ObjectUtil.isNotNull(orderImportTaskDO)) {
                taskExist = true;
                break;
            } else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("====================【线程中断异常】====================");
                }
            }
        }
        if (taskExist) {
            // 更新状态为消费成功
            orderImportTaskMapper.update(new LambdaUpdateWrapper<OrderImportTaskDO>()
                    .eq(OrderImportTaskDO::getId, taskId)
                    .eq(OrderImportTaskDO::getOrganId, organId)
                    .set(OrderImportTaskDO::getStatus, OrderImportTaskStatusEnum.CONSUME_SUCCESS.getStatus()));
        } else {
            String taskNotExistNotify = String.format("%s不存在的导入任务，消费中止", taskId);
            // 更新状态为消费成功，导入失败
            orderImportTaskMapper.update(
                    new LambdaUpdateWrapper<OrderImportTaskDO>()
                            .eq(OrderImportTaskDO::getId, taskId)
                            .eq(OrderImportTaskDO::getOrganId, organId)
                            .set(OrderImportTaskDO::getStatus, OrderImportTaskStatusEnum.CONSUME_SUCCESS.getStatus())
                            .set(OrderImportTaskDO::getImportStatus, OrderImportStatusEnum.IMPORT_FAIL.getStatus())
                            .set(OrderImportTaskDO::getResult, taskNotExistNotify)
            );
            log.error(String.format("====================【%s】====================", taskNotExistNotify));
        }
        return orderImportTaskDO;
    }

}
