package com.yn.bftl.thirdparty.modules.chinaums.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.StringUtils;
import com.yn.bftl.common.modules.account.dto.ExternalIncomeDTO;
import com.yn.bftl.thirdparty.common.exception.YnceErrorException;
import com.yn.bftl.thirdparty.common.util.DateTimeUtils;
import com.yn.bftl.thirdparty.modules.chinaums.dto.ByxChinaumsCallBackDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.MchApplicationsNoticeDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.TradeResultDTO;
import com.yn.bftl.thirdparty.modules.chinaums.dto.byx.ByxMchApplicationsNoticeDTO;
import com.yn.bftl.thirdparty.modules.chinaums.service.AuthService;
import com.yn.bftl.thirdparty.modules.chinaums.service.ChinaumsCallBackService;
import com.yn.bftl.thirdparty.modules.chinaums.service.WalletService;
import com.yn.bftl.thirdparty.modules.chinaums.vo.ChinaumsCallBackVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 银联回调服务实现
 *
 * @author huabiao
 * @create 2022/12/8  19:19
 **/
@Slf4j
@Service
public class ChinaumsCallBackServiceImpl implements ChinaumsCallBackService {

    @Resource
    private AuthService authService;
    @Resource
    private WalletService walletService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public ChinaumsCallBackVO callbackForByx(ByxMchApplicationsNoticeDTO byxMchApplicationsNoticeDTO) {
        log.info("银联回调 - {}", JSON.toJSONString(byxMchApplicationsNoticeDTO));
        synchronized (this) {
            return handleCallBack(byxMchApplicationsNoticeDTO);
        }
    }

    private ChinaumsCallBackVO handleCallBack(ByxMchApplicationsNoticeDTO byxMchApplicationsNoticeDTO) {
        Boolean isSuccess = false;
        switch (byxMchApplicationsNoticeDTO.getMsgType()) {
            case "REG_STATUS_CHANGE":
                JSONObject changedto = byxMchApplicationsNoticeDTO.getMsgBodyObject();
                ByxChinaumsCallBackDTO byxCallBackDTO = changedto.toJavaObject(ByxChinaumsCallBackDTO.class);
                authService.changeChinaumsAuthInfoStatus(byxCallBackDTO);
                isSuccess = true;
                break;
            case "OPEN_C_ACCOUNT_RESULT_NOTIFY":
                break;
            // 商户开户成功通知
            case "REG_OPEN_ACCT_SUCCESS":
                JSONObject dto = byxMchApplicationsNoticeDTO.getMsgBodyObject();
                ByxChinaumsCallBackDTO byxChinaumsCallBackDTO = dto.toJavaObject(ByxChinaumsCallBackDTO.class);
                isSuccess = authService.handleMchCallBackSuccess(byxChinaumsCallBackDTO);
                break;
            case "MERGE_GUARANTEED_PAY":
                String mctOrderNo = byxMchApplicationsNoticeDTO.getMsgBodyObject().get("mctOrderNo") == null ? null : byxMchApplicationsNoticeDTO.getMsgBodyObject().get("mctOrderNo").toString();
                String guaranteedOrderNo = byxMchApplicationsNoticeDTO.getMsgBodyObject().get("guaranteedOrderNo") == null ? null : byxMchApplicationsNoticeDTO.getMsgBodyObject().get("guaranteedOrderNo").toString();
                String orderStatus = byxMchApplicationsNoticeDTO.getMsgBodyObject().get("orderStatus") == null ? null : byxMchApplicationsNoticeDTO.getMsgBodyObject().get("orderStatus").toString();
                if (StringUtils.isEmpty(mctOrderNo)) {
                    log.error("回调（MERGE_GUARANTEED_PAY）：商户订单号为空");
                    throw new YnceErrorException("商户订单号为空");
                }
                TradeResultDTO tradeResultDTO = new TradeResultDTO();
                tradeResultDTO.setOutOrderNo(mctOrderNo);
                tradeResultDTO.setTradeId(guaranteedOrderNo);
                tradeResultDTO.setStatus(orderStatus);
                isSuccess = walletService.payCallback(tradeResultDTO);
                break;
            // 交易结果
            case "trade_result":
                log.info("交易结果通知 交易类型为：{}", byxMchApplicationsNoticeDTO.getMsgBodyObject().get("tradeType"));
                isSuccess = walletService.tradeResult(byxMchApplicationsNoticeDTO.getMsgBodyObject().toJavaObject(TradeResultDTO.class));
                break;
            // 转账入金
//            case "transfer_deposit":
            case "TRANS_NOTIFY":
                JSONObject jsonObject = byxMchApplicationsNoticeDTO.getMsgBodyObject();
                log.info("交易结果通知 交易类型为：{}", jsonObject.get("transTypeName"));

                // 银联交易订单号
                String transOrderNo = jsonObject.getString("transOrderNo");

                ExternalIncomeDTO externalIncomeDTO = new ExternalIncomeDTO();
                externalIncomeDTO.setAmount(jsonObject.getLong("transAmt"));
                externalIncomeDTO.setBalanceAcctId(jsonObject.getString("walletId"));
                externalIncomeDTO.setBalanceAcctNo(jsonObject.getString("bankAcctNo"));
                externalIncomeDTO.setPayBankAcctName(jsonObject.getString("payBankAcctName"));
                externalIncomeDTO.setPayBankAcctNo(jsonObject.getString("payBankAcctNo"));
                externalIncomeDTO.setPayBankCode(jsonObject.getString("payBankCode"));
                externalIncomeDTO.setBankMemo(jsonObject.getString("procResultDscrb"));
                externalIncomeDTO.setRecordedAt(DateTimeUtils.getDateTimeToRFC3339(jsonObject.getString("transTime")) );
                externalIncomeDTO.setTradeId(jsonObject.getString("transOrderNo"));
                externalIncomeDTO.setOrigOutOrderNo(jsonObject.getString("mctOrderNo"));

                if("+".equals(jsonObject.getString("amtSymbol")) ) {
                    externalIncomeDTO.setTradeType("11");
                    // 加锁，避免并发请求
                    String lockKeyTradeId = externalIncomeDTO.getTradeId();
                    Boolean lockTradeId = stringRedisTemplate.opsForValue().setIfAbsent(lockKeyTradeId, lockKeyTradeId);
                    // 拿不到锁直接返回
                    if (!lockTradeId) {
                        throw new YnceErrorException("转账入金(充值)处理中，稍后重试");
                    }
                    stringRedisTemplate.expire(lockKeyTradeId, 1, TimeUnit.MINUTES);
                    try {
                        isSuccess = walletService.transferDeposit(externalIncomeDTO);
                    } finally {
                        // 执行成功和失败都需要删除锁
                        stringRedisTemplate.delete(lockKeyTradeId);
                    }
                }
                else if("-".equals(jsonObject.getString("amtSymbol"))){

                    switch (jsonObject.getString("transType")){
                        // 快速提现、普通提现
                        case "wallbc020008":
                        case "wallbc020009":
                            walletService.withdrawalsCallBack(transOrderNo);
                            break;
                    }
                }
                break;
            default:
                isSuccess = true;
        }
        ChinaumsCallBackVO chinaumsCallBackVO = new ChinaumsCallBackVO();
        if (isSuccess) {
            // 通知成功回复
            JSONObject msgHead = new JSONObject();
            msgHead.put("errCode", "0000");
            msgHead.put("errInfo", "SUCCESS");
            chinaumsCallBackVO.setMsgHead(msgHead);
            chinaumsCallBackVO.setMsgBody(new JSONObject());
        }
        return chinaumsCallBackVO;
    }


    @Override
    public ChinaumsCallBackVO mchApplicationsResult(MchApplicationsNoticeDTO mchApplicationsNoticeDTO) {
        log.info("银联回调 - {}", JSON.toJSONString(mchApplicationsNoticeDTO));
        // 加锁，避免并发请求
        String lockKey = mchApplicationsNoticeDTO.getEventType() + mchApplicationsNoticeDTO.getEventId();
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockKey);
        // 拿不到锁直接返回
        if (!lock) {
            throw new YnceErrorException("该回调在处理中，稍后重试");
        }
        stringRedisTemplate.expire(lockKey, 1, TimeUnit.MINUTES);
        try {
            Boolean isSuccess = false;
            switch (mchApplicationsNoticeDTO.getEventType()) {
                // 二级商户进件通知
//                case "mch_application_finished":
//                    Object mchApplicationId = mchApplicationsNoticeDTO.getEventData().get("mchApplicationId");
//                    if (mchApplicationId != null) {
//                        // 判断时间是否超过30秒，若是则手动处理
//                        LocalDateTime succeededTime = DateTimeUtils.getLocalDateTimeByRFC3339(mchApplicationsNoticeDTO.getEventData().get("succeededAt").toString());
//                        Duration duration = Duration.between(succeededTime, LocalDateTime.now());
//                        if (duration.toMillis() < 30000) {
//                            isSuccess = false;
//                        }else {
//                            isSuccess = authService.handleApplicationStatus("2", mchApplicationId.toString(), null);
//                        }
//                    }
//                    break;
                // 交易结果
                case "trade_result":
                    log.info("交易结果通知 交易类型为：{}", mchApplicationsNoticeDTO.getEventData().get("tradeType"));
                    isSuccess = walletService.tradeResult(mchApplicationsNoticeDTO.getEventData().toJavaObject(TradeResultDTO.class));
                    break;
                // 平台监管账户(母账户)发生入金
                case "root_transfer_deposit":
                    log.info("平台监管账户(母账户)发生入金");
                    isSuccess = true;
                    break;
                // 转账入金
                case "transfer_deposit":
                    log.info("转账入金 交易类型为：{}", mchApplicationsNoticeDTO.getEventData().get("tradeType"));
                    ExternalIncomeDTO externalIncomeDTO = mchApplicationsNoticeDTO.getEventData().toJavaObject(ExternalIncomeDTO.class);
                    // 加锁，避免并发请求
                    String lockKeyTradeId = externalIncomeDTO.getTradeId();
                    Boolean lockTradeId = stringRedisTemplate.opsForValue().setIfAbsent(lockKeyTradeId, lockKeyTradeId);
                    // 拿不到锁直接返回
                    if (!lockTradeId) {
                        throw new YnceErrorException("转账入金(充值)处理中，稍后重试");
                    }
                    stringRedisTemplate.expire(lockKeyTradeId, 1, TimeUnit.MINUTES);
                    try {
                        isSuccess = walletService.transferDeposit(externalIncomeDTO);
                    } finally {
                        // 执行成功和失败都需要删除锁
                        stringRedisTemplate.delete(lockKeyTradeId);
                    }
                    break;
                // 打款金额验证
                case "settle_acct_pay_amount_validation":
                    log.info("打款金额验证");
                    isSuccess = authService.accountValidation(mchApplicationsNoticeDTO.getEventData().get("outRequestNo").toString());
                    break;
                default:
                    isSuccess = true;
            }
            ChinaumsCallBackVO chinaumsCallBackVO = new ChinaumsCallBackVO();
            if (isSuccess) {
                // 通知成功回复
                JSONObject msgHead = new JSONObject();
                msgHead.put("errCode", "0000");
                msgHead.put("errInfo", "SUCCESS");
                chinaumsCallBackVO.setMsgHead(msgHead);
                chinaumsCallBackVO.setMsgBody(new JSONObject());
            }
            return chinaumsCallBackVO;
        }  finally {
            // 执行成功和失败都需要删除锁
            stringRedisTemplate.delete(lockKey);
        }
    }

    public static void main(String[] args) {
        String content = "{\"msgBody\":{\"registerNo\":\"c2814b8bd2c840668098bb9d90510003\"},\"msgType\":\"REG_OPEN_ACCT_SUCCESS\"}";
        // 要保存的字符串
//        String content = "Hello, World!";

        // 指定文件路径
        String filePath = "D:\\output";

        // 将字符串转换为字节数组
        byte[] contentBytes = content.getBytes();

        // 使用try-with-resources语句自动关闭资源
        try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), "UTF-8"))) {
            writer.write(content);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("保存文件时发生错误");
        }

    }

//    public static void main(String[] args) {
//        ByxMchApplicationsNoticeDTO  dto = new ByxMchApplicationsNoticeDTO();
//        dto.setMsgType("REG_OPEN_ACCT_SUCCESS");
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("registerNo", "c2814b8bd2c840668098bb9d90510003");
//        dto.setMsgBody(jsonObject);
//        System.out.println(JSON.toJSONString(dto));
//    }
}
