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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeeplus.common.redis.RedisUtils;
import com.jeeplus.finance.invoice.domain.OMS.InvoiceDown.OMSInvoiceDetailInfo;
import com.jeeplus.finance.invoice.domain.OMS.OMSAccessTokenInfo;
import com.jeeplus.finance.invoice.domain.OMS.OMSInvoiceResultDownloadData;
import com.jeeplus.finance.invoice.mapper.CwFinanceInvoiceMapper;
import com.jeeplus.finance.invoice.service.CwFinanceInvoiceService;
import com.jeeplus.finance.invoice.service.dto.CwFinanceInvoiceDTO;
import com.jeeplus.finance.invoice.util.OMS.HttpPostJsonUtil;
import com.jeeplus.finance.invoice.util.OMS.OMSNationUtil;
import com.jeeplus.finance.utils.Global;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.jeeplus.finance.invoice.config.OmsConfig.*;

/**
 * OMS发票下载
 */
@Service
@Transactional(readOnly = true)
@Lazy
public class InvoiceDownloadService {


    //private static final String appId = Global.getConfig("omsAppId");
    //private static final String appKey = Global.getConfig("omsAppKey");
    //private static final String deptCode = Global.getConfig("omsDeptCode");

    //@Value("${omsAppId}")
    //private String appId;
    //@Value("${omsAppKey}")
    //private String appKey;
    //@Value("${omsDeptCode}")
    //private String deptCode;
    //@Value("${omsUrl}")
    //private String omsUrl;


    @Autowired
    private OMSDisposeService omsDisposeService;

    @Autowired
    private CwFinanceInvoiceService workInvoiceService;
    @Autowired
    private CwFinanceInvoiceMapper workInvoiceDetailDao;



    @Transactional(readOnly = false)
    public void processInvoiceDownloadTasks() {
        RedisUtils jedis = null;
        try {
            jedis = RedisUtils.getInstance();
            Set<String> downloadTaskKeys = jedis.keys("OMS_invoice_download:*");
            if (downloadTaskKeys.isEmpty()) {
                System.out.println("[InvoiceDownloadTask] 暂无待解析的发票任务");
                return;
            }

            // 遍历所有解析任务
            for (String taskKey : downloadTaskKeys) {
                String accessToken =(String) jedis.hGet(taskKey, "accessToken");
                String workInvoiceId = (String) jedis.hGet(taskKey, "workInvoiceId");
                String informType = (String) jedis.hGet(taskKey, "informType");
                //获取当前redis中的accessToken
                //如果有值，则使用当前redis中的accessToken，否则重新生成一个新的accessToken
                accessToken = (String) jedis.get("OMSAccessToken");

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

                String firstExecTimeStr = (String) jedis.hGet(taskKey, "firstExecTime");

                // 参数校验
                if (StringUtils.isAnyBlank(accessToken, firstExecTimeStr)) {
                    jedis.delete(taskKey);
                    continue;
                }

                long firstExecTime = Long.parseLong(firstExecTimeStr);
                // ========== 改动1：超时判断改为23小时（82800000毫秒） ==========
                // 23*60*60*1000 = 82800000 ms（原86400000是24小时）
                if (System.currentTimeMillis() - firstExecTime > 82800000L) {
                    System.err.println("[InvoiceDownloadTask] 任务["+workInvoiceId+"]已重试23小时，触发兜底");
                    omsDisposeService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "发票下载解析失败，请通过税务系统进行查看", informType);
                    jedis.delete(taskKey); // 兜底后删除Redis，保证数据一致
                    continue;
                }

                // ========== 核心：调用原始解析方法（移至此） ==========
                executeInvoiceDownloadWithRetry(accessToken, workInvoiceId, informType);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                //jedis.close();
            }
        }
    }

    /**
     * 执行发票下载分析方法，获取发票下载接口以及其他信息
     * @param accessToken   发票当时的accessToken
     * @param workInvoiceId 发票的id（数据库中work_invoice中对应的id）
     * @param informType 用于流程通知的判定参数
     */

    @Transactional(readOnly = false)
    public void executeInvoiceDownloadWithRetry(String accessToken, String workInvoiceId, String informType) {
        try {
            System.out.println("✅ [InvoiceDownloadTask] 开始解析发票，订单号：" + workInvoiceId);

            // ========== 原始解析逻辑 —— 完全不变 ==========
            OMSInvoiceResultDownloadData getInvoiceInfo = new OMSInvoiceResultDownloadData();
            getInvoiceInfo.setDeptCode(deptCode);
            getInvoiceInfo.setOrderno(workInvoiceId);
            getInvoiceInfo.setIsDetail("1");
            String jsonInvoiceInfoStr = JSON.toJSONString(getInvoiceInfo);
            String base64Str = Base64.getEncoder().encodeToString(jsonInvoiceInfoStr.getBytes(StandardCharsets.UTF_8));

            OMSAccessTokenInfo invoiceDownInfo = new OMSAccessTokenInfo();
            invoiceDownInfo.setAppId(appId);
            invoiceDownInfo.setAppKey(appKey);
            invoiceDownInfo.setExchangeId(UUID.randomUUID().toString());
            invoiceDownInfo.setAccessToken(accessToken);
            invoiceDownInfo.setData(base64Str);
            String jsonInvoiceDownStr = JSON.toJSONString(invoiceDownInfo);

            String invoiceResultStr = HttpPostJsonUtil.doPost(
                    omsUrl +"/prod-api/output/server/invoice/download",
                    jsonInvoiceDownStr
            );
            System.out.println("[InvoiceDownloadTask] 发票解析结果：" + invoiceResultStr);

            String invoceDownJsonStr = null;
            boolean isSuccess = false;
            if (StringUtils.isNotBlank(invoiceResultStr)) {
                OMSAccessTokenInfo resultDownInfo = JSON.parseObject(invoiceResultStr, OMSAccessTokenInfo.class);
                if (null != resultDownInfo.getResult() && "0000".equals(resultDownInfo.getResult().getCode())) {
                    invoceDownJsonStr = OMSNationUtil.getDownFromBase64(resultDownInfo.getData().toString());
                    if (StringUtils.isNotBlank(invoceDownJsonStr)) {
                        OMSInvoiceDetailInfo invoiceInfo = JSONObject.parseObject(invoceDownJsonStr, OMSInvoiceDetailInfo.class);
                        if (invoiceInfo != null) {
                            //根据开票id查询数据并进行修改
                            //需要将错误信息保存到对应开票信息表中
                            CwFinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
                            if(null != workInvoice){
                                if(StringUtils.isBlank(invoiceInfo.getOfdUrl())){
                                    omsDisposeService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "发票信息获取失败，请到税务系统进行获取", informType);
                                }else{
                                    //进行处理
                                    isSuccess = workInvoiceService.updateOmsByIdOnDown(workInvoice, invoiceInfo, informType);
                                }
                            }else{

                                omsDisposeService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "发票信息获取失败，请到税务系统进行获取", informType);
                                return;
                            }
                        }
                    }
                }else if(null != resultDownInfo.getResult() && ("1002".equals(resultDownInfo.getResult().getCode())
                        || "1001".equals(resultDownInfo.getResult().getCode())
                        || "1005".equals(resultDownInfo.getResult().getCode())
                        || "1006".equals(resultDownInfo.getResult().getCode())
                        || "0001".equals(resultDownInfo.getResult().getCode())
                        || "0002".equals(resultDownInfo.getResult().getCode())
                        || "0003".equals(resultDownInfo.getResult().getCode())
                        || "0004".equals(resultDownInfo.getResult().getCode())
                        || "0005".equals(resultDownInfo.getResult().getCode())
                        || "0006".equals(resultDownInfo.getResult().getCode())
                        || "0007".equals(resultDownInfo.getResult().getCode())
                        || "0008".equals(resultDownInfo.getResult().getCode())
                )){
                    omsDisposeService.handleInvoiceRetryAllFail(accessToken, workInvoiceId, "发票信息获取失败，失败原因：" + resultDownInfo.getResult().getMessage(), informType);
                    //删除redis中的数据，防止重复操作
                    deleteInvoiceDownloadTaskFromRedis(workInvoiceId); // 成功删除Redis，保证数据一致
                }
            }

            // ========== 重试规则调整：去掉次数限制，改为23小时超时（由定时任务控制） ==========
            if (isSuccess) {
                System.out.println("✅ [InvoiceDownloadTask] 任务["+workInvoiceId+"]解析成功，删除Redis任务");
                deleteInvoiceDownloadTaskFromRedis(workInvoiceId); // 成功删除Redis，保证数据一致
                return;
            } else {
                System.out.println("❌ [InvoiceDownloadTask] 任务["+workInvoiceId+"]解析失败，5分钟后重试");
                // 无需手动延迟，由定时任务每5分钟扫描即可
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("❌ [InvoiceDownloadTask] 任务["+workInvoiceId+"]解析抛出异常，5分钟后重试");
            // 异常不删除Redis，由定时任务继续重试
        }
    }

    // ========== 辅助方法：删除Redis解析任务 ==========
    private void deleteInvoiceDownloadTaskFromRedis(String orderno) {
        RedisUtils jedis = null;
        try {
            jedis = RedisUtils.getInstance();
            jedis.delete("OMS_invoice_download:" + orderno);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                //jedis.close();
            }
        }
    }

}
