package com.cf.imes.module.system.service.funds.advertisement;

import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementDO;
import com.cf.imes.module.system.dal.dataobject.funds.advertisement.AdvertisementTaskDO;
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementMapper;
import com.cf.imes.module.system.dal.mysql.funds.advertisement.AdvertisementTaskMapper;
import com.cf.imes.module.system.enums.advertisement.AdvertisementStatusEnum;
import com.cf.imes.module.system.enums.advertisement.MessageStatusEnum;
import com.cf.imes.module.system.mq.message.advertisement.AdvertisementSendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.context.request.RequestContextHolder;

import jakarta.annotation.Resource;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE;
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY;

/**
 * 广告状态修改 Service 实现类
 *
 */
@Service
@Validated
@Slf4j
public class AdvertisementCompensateTask {

    @Resource
    private AdvertisementMapper advertisementMapper;

    @Resource
    private AdvertisementTaskMapper advertisementTaskMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;


    //=== 补偿任务 ===//
//    @Scheduled(cron = "0 0/30 * * * ?")
    public void checkAdStatusConsistency() {
        // 1. 检查应发布但未发布的广告
        List<AdvertisementDO> unpublishedAds = advertisementMapper.selectList(LocalDate.now().atStartOfDay(), AdvertisementStatusEnum.UNPUBLISHED.getStatus());
        unpublishedAds.forEach(ad -> {
            updateAdStatus(ad, AdvertisementStatusEnum.PUBLISHED.getStatus());
            rescheduleExpireMessage(ad);
        });

        // 2. 检查应结束但未结束的广告
        List<AdvertisementDO> publishedAds = advertisementMapper.selectList(
                new QueryWrapper<AdvertisementDO>()
                        .le("end_time", LocalDateTime.now())
                        .eq("status", AdvertisementStatusEnum.PUBLISHED.getStatus())
        );
        publishedAds.forEach(ad -> updateAdStatus(ad, AdvertisementStatusEnum.ENDED.getStatus()));
    }

    private void rescheduleExpireMessage(AdvertisementDO ad) {
        if (ad.getEndTime().isAfter(LocalDate.now())) {
            String newMsgId = sendSingleMessage(ad.getId(), "expire", ad.getEndTime().atStartOfDay());
            trackMessage(ad.getId(), newMsgId, AdvertisementStatusEnum.PUBLISHED.getStatus(), MessageStatusEnum.CANCELLED.getStatus());
        }
    }

    private void updateAdStatus(AdvertisementDO ad, Integer newStatus) {
        advertisementMapper.updateAdStatus(ad.getId(), newStatus);

    }

    /**
     * 发送单个延迟消息
     */
    private String sendSingleMessage(Long adId, String action, LocalDateTime triggerTime) {
        String messageId = UUID.randomUUID().toString();
        long delay = Duration.between(LocalDateTime.now(), triggerTime).toMillis();


        if (delay > 0) {
            RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);

            rabbitTemplate.convertAndSend(
                    SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_EXCHANGE,
                    SYSTEM_ADVERTISEMENT_UPDATE_DELAYED_ROUTING_KEY,
                    new AdvertisementSendMessage(adId, messageId, action),
                    correlationData -> {
                        correlationData.getMessageProperties().setMessageId(messageId);
                        correlationData.getMessageProperties().setDelayLong(Long.valueOf(delay));
                        return correlationData;
                    }
            );
        }
        return messageId;
    }

    /**
     * 记录消息追踪
     */
    private void trackMessage(Long adId, String messageId, Integer advertisementStatus, Integer messageStatus) {
        if (StringUtils.isNotBlank(messageId)) {
            advertisementTaskMapper.insert(new AdvertisementTaskDO()
                    .setAdvertisementId(adId)
                    .setMessageId(messageId)
                    .setMessageStatus(messageStatus)
                    .setAdvertisementStatus(advertisementStatus)
            );
            log.info("[trackMessage][adId({}) messageId({}) 记录消息追踪成功]", adId, messageId);
        }
    }
}
