package com.jeequan.jeepay.thirdparty.channel.yspay;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ServiceException;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.model.autopos.ChannelOrderAcceptParams;
import com.jeequan.jeepay.core.model.autopos.ChannelOrderAcceptRetMsg;
import com.jeequan.jeepay.core.model.context.MchAppConfigContext;
import com.jeequan.jeepay.core.model.params.IsvParams;
import com.jeequan.jeepay.core.model.params.yspay.YspayIsvParams;
import com.jeequan.jeepay.core.model.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.thirdparty.channel.AbstractChannelOrderAcceptService;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.AESUtil;
import com.jeequan.jeepay.thirdparty.channel.yspay.utils.YspayKit;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 智能POS回调
 *
 * @author zx
 *
 * @date 2021-06-07 07:15
 */
@Service
@Slf4j
public class YspayChannelOrderAcceptService extends AbstractChannelOrderAcceptService {

    @Override
    public String getIfCode() {
        return CS.IF_CODE.YSPAY;
    }
    public JSONObject getReturnJson() {
        JSONObject returnJson = new JSONObject();
        returnJson.put("code", "00");
        returnJson.put("msg", "成功");
        return returnJson;
    }

    @Override
    public ChannelOrderAcceptParams parseParams(HttpServletRequest request, IsvParams isvParams) {

        try {

            String bodyStr = getBody(request);
            YspayIsvParams yspayIsvParams = (YspayIsvParams) isvParams;
            String posPrivateKey = yspayIsvParams.getPosPrivateKey();
            String strAes = AESUtil.decryptStrAES(bodyStr, posPrivateKey);
            JSONObject params = JSON.parseObject(strAes);

            log.info("银盛智能POS【订单通知模式】通知参数, 通知参数：{}, 解密参数：{}", bodyStr, strAes);

            String deviceNo = params.getString("t41TrmNo");
            String payStatus = params.getString("transType");

            String tradeType = ""; // 交易状态：1.支付成功，2退款成功，3撤销成功，4冲正成功
            if (POS_TRANS_TYPE_PAY_MAP.get(payStatus) != null && POS_TRANS_TYPE_PAY_MAP.get(payStatus)) {
                tradeType = ChannelOrderAcceptParams.TRADE_TYPE_PAYMENT;
            }else if (POS_TRANS_TYPE_REFUND_MAP.get(payStatus) != null && POS_TRANS_TYPE_REFUND_MAP.get(payStatus)) {
                tradeType = ChannelOrderAcceptParams.TRADE_TYPE_REFUND;
            }

            return ChannelOrderAcceptParams.buildAutoPosParams(tradeType, deviceNo, params);

        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("FAIL");
        }
    }

    @Override
    public ChannelOrderAcceptRetMsg payNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) {
        try {
            String logPrefix = "银盛智能POS【订单通知模式】  支付通知";

            ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg();
            result.setChannelState(ChannelRetMsg.ChannelState.WAITING);

            // 获取请求参数
            JSONObject jsonParams = (JSONObject) params;

//            // 签名参数
//            String checkValue = jsonParams.getString("checkValue");
//
//            // 验签
//            boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, ifCode, checkValue, logPrefix);
//            if(!verifyResult){
//                log.info("{}验证通知数据及签名失败", logPrefix);
//                throw ResponseException.buildText("FAIL");
//            }

            // 支付状态
            String status = jsonParams.getString("txnSts");
            // 支付成功
            if (YspayKit.POS_CODE_S.equals(status)) {
                result.setResponseEntity(jsonResp(getReturnJson())); // 通知上游处理成功
                result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);

                // 交易类型：01-银联云闪付 02-微信 03-支付宝
                String payType = jsonParams.getString("payType");

                // 扫码支付参考号，扫码交易时存在且唯一
                String channelOrderId = jsonParams.getString("logNo");

                result.setChannelOrderId(channelOrderId); // 渠道订单号，必填
//                result.setChannelUserId(reqData.getString("buyer_id"));

                result.setChannelAmount(jsonParams.getLong("t4TxnAmt"));  // 订单金额，单位分，必填
                result.setChannelWayCode(CS.PAY_WAY_CODE.AUTO_POS); // 支付方式，必填
                result.setChannelWayCodeType(covertWayCodeType(payType)); // 支付方式类型，必填
                result.setBizOrderId(StringUtils.isNotBlank(jsonParams.getString("logNo")) ? jsonParams.getString("logNo").trim() : "");
            }
            return result;

        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("FAIL");
        }
    }

    @Override
    public ChannelOrderAcceptRetMsg refundNotice(HttpServletRequest request, Object params, MchAppConfigContext mchAppConfigContext, String ifCode) {
        try {
            String logPrefix = "银盛智能POS【订单通知模式】  退款通知";

            ChannelOrderAcceptRetMsg result = new ChannelOrderAcceptRetMsg();
            result.setChannelState(ChannelRetMsg.ChannelState.WAITING);

            // 获取请求参数
            JSONObject jsonParams = (JSONObject) params;
            log.info("{} 通知参数, jsonParams：{}", logPrefix, jsonParams);

//            // 签名参数
//            String checkValue = jsonParams.getString("checkValue");
//
//            // 验签
//            boolean verifyResult = validateSign(jsonParams, mchAppConfigContext, ifCode, checkValue, logPrefix);
//            if(!verifyResult){
//                log.info("{}验证通知数据及签名失败", logPrefix);
//                throw ResponseException.buildText("FAIL");
//            }

            // 退款状态
            String status = jsonParams.getString("txnSts");
            // 退款成功
            if (YspayKit.POS_CODE_S.equals(status)) {
                result.setResponseEntity(jsonResp(getReturnJson())); // 通知上游处理成功
                result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
                result.setChannelOrderId(jsonParams.getString("ologNo")); // 渠道退款订单号，必填

                // 交易类型：01-银联云闪付 02-微信 03-支付宝
                String payType = jsonParams.getString("payType");

                // 扫码支付参考号，扫码交易时存在且唯一
                String channelOrderId = jsonParams.getString("ologNo");

                result.setChannelAmount(jsonParams.getLong("t4TxnAmt"));  // 退款金额，单位分，必填
                result.setChannelPayOrderId(channelOrderId);  // 原渠道订单号（和支付订单渠道订单号一致），退款必填
                result.setBizOrderId(StringUtils.isNotBlank(jsonParams.getString("ologNo")) ? jsonParams.getString("ologNo").trim() : "");
            }
            return result;

        } catch (Exception e) {
            log.error("error", e);
            throw ResponseException.buildText("FAIL");
        }
    }

    private String covertWayCodeType(String payType) {
        switch (payType){
            case "01": return CS.PAY_WAY_CODE_TYPE.UNIONPAY;
            case "02": return CS.PAY_WAY_CODE_TYPE.WECHAT;
            case "03": return CS.PAY_WAY_CODE_TYPE.ALIPAY;
            default:  return CS.PAY_WAY_CODE_TYPE.OTHER;
        }
    }

    /**
     * 验签
     * @return
     */
    public boolean validateSign(JSONObject jsonParams, MchAppConfigContext mchAppConfigContext, String ifCode, String reqSign, String logPrefix) {

        // 交易数据
        YspayIsvParams isvParams = (YspayIsvParams) configContextQueryService.queryIsvParams(mchAppConfigContext.getMchApplyment().getIsvNo(), ifCode);

        // 商户号
        String signStr = jsonParams.getString("t42MercId") +
                // 终端号
                jsonParams.getString("t41TrmNo") +
                // 订单号
                jsonParams.getString("logNo") +
                // 日期
                jsonParams.getString("acDt") +
                // 私钥
                isvParams.getPosPrivateKey();

        log.info("{}待验签字符串：{}, ", logPrefix, signStr);
        String md5Result = SecureUtil.md5(signStr);

        return StringUtils.equalsIgnoreCase(reqSign, md5Result);
    }

    /**
     * 获取请求数据
     *
     * @param request
     * @return
     */
    protected final String getBody(HttpServletRequest request) {
        try {
            @Cleanup InputStreamReader in = new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8);
            StringBuilder bf = new StringBuilder();
            int len;
            char[] chs = new char[1024];
            while ((len = in.read(chs)) != -1) {
                bf.append(new String(chs, 0, len));
            }
            return bf.toString();
        } catch (Exception e) {
            log.error("请求头部取数据异常：{}", e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    public static final Map<String, Boolean> POS_TRANS_TYPE_PAY_MAP = new HashMap<>();
    static {
        POS_TRANS_TYPE_PAY_MAP.put("2010020", true);    // 消费
        POS_TRANS_TYPE_PAY_MAP.put("2010010", true);    // 消费冲正
        POS_TRANS_TYPE_PAY_MAP.put("1300001", true);    // 聚合扫码支付
        POS_TRANS_TYPE_PAY_MAP.put("2080001", true);    // 微信反扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2080010", true);    // 微信正扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2070001", true);    // 支付宝反扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2070008", true);    // 支付宝终端正扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2050001", true);    // 银联反扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2050008", true);    // 银联正扫支付
        POS_TRANS_TYPE_PAY_MAP.put("2090028", true);    // 订单支付
        POS_TRANS_TYPE_PAY_MAP.put("2020001", true);    // 扫码快付支付
        POS_TRANS_TYPE_PAY_MAP.put("2050009", true);    // 银联固定二维码支付
        POS_TRANS_TYPE_PAY_MAP.put("2080006", true);    // 微信公众号支付
        POS_TRANS_TYPE_PAY_MAP.put("2070009", true);    // 支付宝公众号支付

        /** 预授权完成请求和完成通知  是支付成功的 **/
    }
    public static final Map<String, Boolean> POS_TRANS_TYPE_REFUND_MAP = new HashMap<>();
    static {
        POS_TRANS_TYPE_REFUND_MAP.put("2010080", true);    // 退货
        POS_TRANS_TYPE_REFUND_MAP.put("2010030", true);    // 消费撤销
        POS_TRANS_TYPE_REFUND_MAP.put("1300004", true);    // 聚合扫码退款
        POS_TRANS_TYPE_REFUND_MAP.put("2080004", true);    // 微信支付退款
        POS_TRANS_TYPE_REFUND_MAP.put("2070004", true);    // 支付宝退款
        POS_TRANS_TYPE_REFUND_MAP.put("2050004", true);    // 银联二维码退款
        POS_TRANS_TYPE_REFUND_MAP.put("2090032", true);    // 订单支付撤销
    }

}
