package com.yiqi.delay.impl;

import cn.hutool.json.JSONUtil;
import com.yiqi.common.core.domain.R;
import com.yiqi.common.enums.*;
import com.yiqi.delay.DelayMessage;
import com.yiqi.delay.DelayQueueCache;
import com.yiqi.order.domain.OrderPayInfo;
import com.yiqi.order.domain.dto.PayRefundDTO;
import com.yiqi.order.domain.dto.PayResponseDTO;
import com.yiqi.order.domain.dto.RefundResponseDTO;
import com.yiqi.order.service.IPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class DelayTaskRunService {

    @Autowired
    private IPayService payService;

    @Autowired
    private DelayQueueCache delayQueueCache;

    /**
     * 延迟任务处理结果枚举
     */
    private enum TaskResult {
        SUCCESS,    // 处理成功
        FAIL,      // 处理失败
        RETRY      // 需要重试
    }

    /**
     * 处理延迟队列消息
     *
     * @param tags         任务标签
     * @param delayMessage 延迟消息
     */
    public void handleDelayMessage(String tags, DelayMessage delayMessage) {
        try {
            // 1. 获取任务处理器
            DelayTagsEnum taskType = DelayTagsEnum.valueOf(tags);
            if (taskType == null) {
                log.error("未知的任务类型: {}", tags);
                return;
            }

            // 2. 根据任务类型处理
            switch (taskType) {
            case ORDER_PAY_DELAY_QUEUE:
                    handleOrderPayQuery(delayMessage);
                    break;
                case ORDER_REUND_DELAY_QUEUE_TASK:
                    handleOrderRefundQuery(delayMessage);
                    break;
                default:
                    log.warn("不支持的任务类型: {}", tags);
                    break;
            }

        } catch (Exception e) {
            log.error("处理延迟任务异常: {}, message: {}", tags, delayMessage, e);
            handleTaskError(delayMessage, e);
        }
    }

    /**
     * 处理支付查询任务
     */
    private void handleOrderPayQuery(DelayMessage delayMessage) {
        // 1. 解析任务数据
                OrderPayInfo orderPayInfo = JSONUtil.toBean(delayMessage.getData(), OrderPayInfo.class);
        log.info("开始处理支付查询任务: {}", orderPayInfo.getOrderNo());

        try {
            // 2. 查询支付结果
            PayResponseDTO payResponse = payService.orderPayQuery(orderPayInfo);
            log.info("支付查询结果: {}, 订单号: {}", payResponse.getPayResult(), orderPayInfo.getOrderNo());

            // 3. 处理查询结果
            TaskResult result = handlePayQueryResult(payResponse, orderPayInfo);

            // 4. 根据结果处理
            switch (result) {
                case SUCCESS:
                    // 处理成功,删除任务
                    delayQueueCache.deleteDelayJob(orderPayInfo.getRequestNo());
                    break;

                case FAIL:
                    // 处理失败,删除任务
                    delayQueueCache.deleteDelayJob(orderPayInfo.getRequestNo());
                    log.error("支付失败: {}", orderPayInfo.getOrderNo());
                    break;

                case RETRY:
                    // 需要重试,更新任务
                    handleTaskRetry(delayMessage, PayQueryTimesEnum.class);
                    break;
            }

        } catch (Exception e) {
            log.error("处理支付查询任务异常: {}", orderPayInfo.getOrderNo(), e);
            handleTaskError(delayMessage, e);
        }
    }

    /**
     * 处理支付查询结果
     */
    private TaskResult handlePayQueryResult(PayResponseDTO response, OrderPayInfo orderPayInfo) {
        // 1. 支付成功
        if (PayResult.success.getCode() == response.getPayResult()) {
            R result = payService.unifiePaySuccessNotify(
                    orderPayInfo.getRequestNo(),
                    orderPayInfo.getOrderNo(),
                    response.getOutTradeNo()
            );

            return R.isSuccess(result) ? TaskResult.SUCCESS : TaskResult.RETRY;
        }

        // 2. 支付失败 
        if (PayResult.fail.getCode() == response.getPayResult()) {
            return TaskResult.FAIL;
        }

        // 3. 其他情况重试
        return TaskResult.RETRY;
    }

    /**
     * 处理退款查询任务
     */
    private void handleOrderRefundQuery(DelayMessage delayMessage) {
        // 1. 解析任务数据
        PayRefundDTO refundDTO = JSONUtil.toBean(delayMessage.getData(), PayRefundDTO.class);
        log.info("开始处理退款查询任务: {}", refundDTO.getOrderNo());

        try {
            // 2. 查询退款结果
            RefundResponseDTO refundResponse = payService.orderRefundQuery(refundDTO);
            log.info("退款查询结果: {}, 订单号: {}", refundResponse.getRefundResult(), refundDTO.getOrderNo());

            // 3. 处理查询结果
            TaskResult result = handleRefundQueryResult(refundResponse, refundDTO);

            // 4. 根据结果处理
            switch (result) {
                case SUCCESS:
                    delayQueueCache.deleteDelayJob(refundDTO.getOutRequestNo());
                    break;

                case FAIL:
                    delayQueueCache.deleteDelayJob(refundDTO.getOutRequestNo());
                    log.error("退款失败: {}", refundDTO.getOrderNo());
                    break;

                case RETRY:
                    handleTaskRetry(delayMessage, RefundQueryTimesEnum.class);
                break;
            }

        } catch (Exception e) {
            log.error("处理退款查询任务异常: {}", refundDTO.getOrderNo(), e);
            handleTaskError(delayMessage, e);
        }
    }

    /**
     * 处理退款查询结果
     */
    private TaskResult handleRefundQueryResult(RefundResponseDTO response, PayRefundDTO refundDTO) {
        // 1. 退款成功
        if (PayResult.success.getCode() == (response.getRefundResult())) {
            R result = payService.unifieRefundSuccessNotify(
                    refundDTO.getOutRequestNo(),
                    refundDTO.getOrderNo(),
                    null
            );

            return R.isSuccess(result) ? TaskResult.SUCCESS : TaskResult.RETRY;
        }

        // 2. 退款失败
        if (PayResult.fail.getCode() == (response.getRefundResult())) {
            return TaskResult.FAIL;
        }

        // 3. 其他情况重试
        return TaskResult.RETRY;
    }

    /**
     * 处理任务重试
     */
    private <T extends Enum<T>> void handleTaskRetry(DelayMessage delayMessage, Class<T> enumClass) {
        // 1. 更新重试次数
                        delayMessage.setPollingNum(delayMessage.getPollingNum() + 1);

        // 2. 检查重试次数是否超限
        int maxRetryCount = getMaxRetryCount(delayMessage.getTags());
        if (delayMessage.getPollingNum() > maxRetryCount) {
            log.warn("任务重试次数超限,删除任务: {}", delayMessage.getUniqueKey());
            delayQueueCache.deleteDelayJob(delayMessage.getUniqueKey());
            return;
        }

        // 3. 计算下次重试时间
        long delayTime = getRetryDelayTime(enumClass, delayMessage.getPollingNum());

        // 4. 重新加入延迟队列
        delayQueueCache.addDelayJob(delayMessage, delayTime);
        log.info("任务进入重试队列: {}, 重试次数: {}, 延迟时间: {}s",
                delayMessage.getUniqueKey(),
                delayMessage.getPollingNum(),
                delayTime);
    }

    /**
     * 获取重试延迟时间
     *
     * @param enumClass  任务类型枚举
     * @param retryCount 当前重试次数
     * @return 延迟时间(秒)
     */
    private <T extends Enum<T>> long getRetryDelayTime(Class<T> enumClass, int retryCount) {
        // 1. 支付查询延迟时间配置(单位:秒)
        int[] payQueryDelays = new int[]{
                3, 3,   // 前2次 15秒
                4, 4,   // 接下来2次 30秒
                5, 5,   // 接下来2次 1分钟
                5, 6,  // 接下来2次 2分钟
                5, 6,  // 接下来2次 3分钟
                10, 30,  // 接下来2次 5分钟
                100, 900,  // 接下来2次 10分钟
                7200, 3600 * 4 // 最后2次 30分钟
        };

        // 2. 退款查询延迟时间配置(单位:秒)
        int[] refundQueryDelays = new int[]{
                10, 20,  // 前2次 15秒
                30, 200,  // 接下来2次 30秒
                3600, 3600 * 2,  // 接下来2次 1分钟
                3600 * 4       // 最后1次 5分钟
        };

        try {
            // 3. 根据任务类型选择对应的延迟时间配置
            int[] delays;
            if (enumClass == PayQueryTimesEnum.class) {
                delays = payQueryDelays;
            } else if (enumClass == RefundQueryTimesEnum.class) {
                delays = refundQueryDelays;
                } else {
                // 默认延迟时间配置
                delays = new int[]{15, 30, 60, 120, 300};
            }

            // 4. 获取对应重试次数的延迟时间
            int index = retryCount - 1;
            if (index >= 0 && index < delays.length) {
                return delays[index];
            }

            // 5. 超出配置范围,使用最后一个配置的延迟时间
            return delays[delays.length - 1];

        } catch (Exception e) {
            log.error("获取重试延迟时间异常", e);
            // 6. 发生异常时返回默认延迟时间(1分钟)
            return 60;
        }
    }

    /**
     * 处理任务异常
     */
    private void handleTaskError(DelayMessage delayMessage, Exception e) {
        // 1. 记录异常信息
        log.error("任务处理异常: {}", delayMessage.getUniqueKey(), e);

        // 2. 重试处理
//        handleTaskRetry(delayMessage, PayQueryTimesEnum.class);
    }

    /**
     * 获取最大重试次数
     */
    private int getMaxRetryCount(String tags) {
        if (DelayTagsEnum.ORDER_PAY_DELAY_QUEUE.name().equals(tags)) {
            return 16; // 支付查询最大重试16次
        } else if (DelayTagsEnum.ORDER_REUND_DELAY_QUEUE_TASK.name().equals(tags)) {
            return 7;  // 退款查询最大重试7次
        }
        return 5;     // 默认最大重试5次
    }
}
