package com.ai.da.common.RabbitMQ;


import com.ai.da.common.utils.MailUtil;
import com.ai.da.model.dto.BasicEmailParamDTO;
import com.ai.da.service.EmailService;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.core.exception.RetryableException;
import org.springframework.amqp.core.Message;

import javax.annotation.Resource;

import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class EmailRetryConsumer {

    @Resource
    private MailUtil mailUtil;
    @Resource
    private MQPublisher mqPublisher;
    @Resource
    private EmailService emailService;

//    @RabbitListener(queues = "#{rabbitMQProperties.deadLetter.queue}")
    public void handleRetry(Map<String, String> mailParams, Message message, Channel channel) throws IOException {
        long tag = message.getMessageProperties().getDeliveryTag();
        try {
            log.info("死信队列收到消息：{}", message);
            // 处理邮件发送参数
            BasicEmailParamDTO basicEmailParamDTO = JSONObject.parseObject(mailParams.get("dto"), BasicEmailParamDTO.class);
            String fileName = mailParams.get("filename");
            InputStreamSource inputStreamSource = Objects.isNull(mailParams.get("source")) ?
                    null : JSONObject.parseObject(mailParams.get("source"), InputStreamSource.class);
            JSONObject templateParams = JSONObject.parseObject(mailParams.get("templateParams"), JSONObject.class);
            String templateName = mailParams.get("templatePath");
            long logId = Long.parseLong(mailParams.get("logId"));
            basicEmailParamDTO.setContent(mailUtil.setContent(templateParams, templateName));
            // 发邮件
            int lastReturnCode = mailUtil.sendMail(basicEmailParamDTO, fileName, inputStreamSource);
            if (lastReturnCode == 250) {
                log.info("邮件发送成功！Subject : {}", basicEmailParamDTO.getSubject());
                emailService.updateStatus(logId, EmailService.DELIVERED);
            } else if (lastReturnCode == 450) {
                log.info("目标邮箱 {} 暂时不可用，请稍后重试", (Object) basicEmailParamDTO.getMailTo());
                // 重试
                retry(mailParams, message, channel, tag, logId);
            } else if (lastReturnCode == 550) {
                log.info("目标邮箱 {} 不可用，邮件发送失败", (Object) basicEmailParamDTO.getMailTo());
                emailService.updateStatus(logId, EmailService.FAILED);
            } else {
                log.info("邮件发送失败，Subject : {}, 状态码: {}", basicEmailParamDTO.getSubject(), lastReturnCode);
                retry(mailParams, message, channel, tag, logId);
                emailService.updateStatus(logId, EmailService.FAILED);
            }
            channel.basicAck(tag, false);
        } catch (RetryableException e) {
            log.info("邮件重试发生异常:RetryableException -> {}", e.getMessage());
            channel.basicAck(tag, false); // 确认原消息
        } catch (Exception e) {
            log.info("邮件重试发生异常:Exception -> {}", e.getMessage());
            channel.basicAck(tag, false); // 确认原消息
        }
    }

    private int getRetryAttempt(Message message)  {
        Integer attempt = message.getMessageProperties()
                .getHeader("x-retry-attempt");
        return attempt != null ? attempt : 1;
    }

    private void retry(Map<String, String> mailParams, Message message, Channel channel, long tag, long logId) throws IOException{
        int attempt = getRetryAttempt(message);
        if (attempt >= 3) { // 最大重试次数
            channel.basicReject(tag, false);
            emailService.updateStatus(logId, EmailService.FAILED);
            log.error("重试结束，邮件最终发送失败: {}", mailParams);
        } else {
            log.info("重新将邮件信息发送到重试队列");
            mqPublisher.sendEmailMsg(mailParams, attempt);
            channel.basicAck(tag, false); // 确认原消息
            // 更新数据库
            emailService.updateRetryCount(logId, attempt + 1);
        }
    }

}
