package com.jeeplus.assess.invoice.service.OMS;

import com.alibaba.fastjson.JSON;
import com.jeeplus.assess.invoice.domain.OMS.OMSAccessTokenInfo;
import com.jeeplus.assess.invoice.mapper.FinanceInvoiceMapper;
import com.jeeplus.assess.invoice.service.dto.FinanceInvoiceDTO;
import com.jeeplus.assess.invoice.utils.OMS.HttpPostJsonUtil;
import com.jeeplus.common.redis.RedisUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.jeeplus.assess.invoice.config.FinanceOmsConfig.*;

/**
 * 用于开发票都用订单接口推送时使用，用来当返回值时9998时进行处理
 * 核心规则：
 * 1. 每2分钟执行一次定时任务（无时段限制）
 * 2. 单个任务最多重试20次（每次间隔2分钟，由定时任务频率控制）
 * 3. 仅判断Redis中是否有任务：有则执行，无则跳过
 * 4. 9998错误纳入重试计数，次数用尽后按失败处理+删除Redis任务
 */
@Service
@Transactional(readOnly = true)
@Lazy(false) // 非懒加载，项目启动即初始化
public class RedInvoiceRetryScheduledService {

    // 原业务类中的核心方法需要能被定时任务调用，建议将executeOrderUploadRetry、handleInvoiceRetryAllFail等方法改为public，
    // 或通过@Autowired注入业务类实例（假设你的业务类叫InvoiceOMSService）
    @Autowired
    private OMSDisposeService invoiceOMSService; // 替换为你实际的业务类名

    @Autowired
    private FinanceInvoiceMapper workInvoiceDao;

    /**
     * 定时任务：每5分钟执行一次（硬编码300000毫秒=5分钟）
     * fixedRate：固定间隔执行，直接写死5分钟
     */
    @Transactional(readOnly = false)
    public void handleInvoice9998RetryTask() {
        RedisUtils jedis = null;
        try {
            jedis = RedisUtils.getInstance();
            // 1. 扫描所有9998重试任务的Redis Key
            Set<String> redisKeys = jedis.keys("PG_OMS_invoice_retry_scheduled:*");
            if (redisKeys == null || redisKeys.isEmpty()) {
                System.out.println("ℹ️ 暂无9998重试任务需要处理");
                return;
            }
            System.out.println("ℹ️ 发现" + redisKeys.size() + "个9998重试任务，开始处理");

            // 2. 遍历每个任务Key，逐个处理
            for (String redisKey : redisKeys) {
                String orderNo = redisKey.split(":")[1];
                try {
                    // 3. 获取Redis中的任务数据
                    Map<Object, Object> rawMap = jedis.hGetAll(redisKey);
                    Map<String, String> taskMap = new HashMap<>();
                    if (rawMap != null) {
                        for (Map.Entry<Object, Object> entry : rawMap.entrySet()) {
                            taskMap.put(
                                    String.valueOf(entry.getKey()),
                                    String.valueOf(entry.getValue())
                            );
                        }
                    }
                    String jsonInvoiceStr = taskMap.get("jsonInvoiceStr");
                    String accessToken = taskMap.get("accessToken");
                    String getKey = taskMap.get("getKey");
                    String initiationType = taskMap.get("initiationType");
                    String retryTimesStr = taskMap.get("retryTimes");
                    String informType = taskMap.get("informType");
                    String workInvoiceId = taskMap.get("workInvoiceId");

                    //获取当前redis中的accessToken
                    //如果有值，则使用当前redis中的accessToken，否则重新生成一个新的accessToken
                    accessToken =(String) jedis.get("PGOMSAccessToken");

                    if(StringUtils.isBlank(accessToken)){
                        // 获取AccessToken 9998重试5次
                        accessToken = invoiceOMSService.getOmsAccessTokenWithRetry(5, "accessToken", workInvoiceId, informType);
                        if(StringUtils.isNotBlank(accessToken)){
                            jedis.setEx("PGOMSAccessToken", accessToken,86400, TimeUnit.SECONDS);
                            System.out.println("重新获取token成功，存入Redis");
                        } else {
                            accessToken = "";
                            System.out.println("获取token失败");
                            return;
                        }
                    }

                    // 校验必要参数
                    if (StringUtils.isBlank(jsonInvoiceStr) || StringUtils.isBlank(orderNo) || StringUtils.isBlank(retryTimesStr)) {
                        System.err.println("❌ 订单" + orderNo + "任务数据不完整，删除无效任务");
                        jedis.delete(redisKey);
                        continue;
                    }

                    // 4. 核心：重试次数扣减（先减1，再判断逻辑）
                    int remainRetryTimes = Integer.parseInt(retryTimesStr);
                    int newRemainTimes = remainRetryTimes - 1; // 每次处理减1

                    // 5. 判断是否耗尽次数（第20次，newRemainTimes=0）
                    if (newRemainTimes <= 0) {
                        System.err.println("❌ 订单" + orderNo + "重试次数已耗尽（累计20次），执行兜底逻辑handleInvoiceRetryAllFail");
                        invoiceOMSService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "重试次数已耗尽（累计20次），需要重新发起申请", informType);
                        jedis.delete(redisKey); // 删除Redis任务，不再重试
                        continue;
                    }

                    // 6. 次数未耗尽：更新Redis中的重试次数，再调用接口重试
                    jedis.hPut(redisKey, "retryTimes", String.valueOf(newRemainTimes));
                    System.out.println("ℹ️ 订单" + orderNo + "剩余重试次数更新为：" + newRemainTimes);

                    FinanceInvoiceDTO workInvoice = workInvoiceDao.queryById(workInvoiceId);
                    if(null != workInvoice){
                        // 7. 调用OMS订单上传接口重试
                        String newResultStr = HttpPostJsonUtil.doPost(
                                omsUrl +"/prod-api/output/server/order/upload",
                                jsonInvoiceStr
                        );
                        System.out.println("✅ 订单" + orderNo + "9998重试调用接口返回：" + newResultStr);

                        workInvoice.setOrderForGoodsResultStr(newResultStr);

                        workInvoiceDao.updateOrderForGoodsResultStrById(workInvoice);


                        // 8. 根据接口返回码处理Redis任务
                        OMSAccessTokenInfo resultTokenInfo = JSON.parseObject(newResultStr, OMSAccessTokenInfo.class);
                        if (resultTokenInfo != null && resultTokenInfo.getResult() != null) {
                            // 9. 调用核心重试逻辑处理返回结果
                            Map<String, Object> resultMap = new HashMap<>();
                            invoiceOMSService.executeOrderUploadRetry(
                                    workInvoiceId,
                                    newRemainTimes, // 传入扣减后的剩余次数
                                    newResultStr,
                                    jsonInvoiceStr,
                                    accessToken,
                                    resultMap,
                                    getKey,
                                    initiationType
                                    , informType
                            );
                            jedis.delete(redisKey);
                        }/* else {
                        // 解析返回结果失败：执行兜底+删除任务
                        System.err.println("❌ 订单" + orderNo + "9998重试返回结果解析失败，执行兜底逻辑");
                        invoiceOMSService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "9998重试返回结果解析失败");
                        jedis.del(redisKey);
                    }*/
                    }




                } catch (Exception e) {
                    e.printStackTrace();
                    System.err.println("❌ 处理订单" + orderNo + "9998重试任务异常：" + e.getMessage());
                    // 异常时不删除任务，下次继续重试（避免因临时异常丢失任务）
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("❌ 9998重试定时任务执行异常：" + e.getMessage());
        } finally {
            if (jedis != null) {
                //jedis.close();
            }
        }
    }
}