package com.hzs.third.pay.controller.api;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.huifu.bspay.sdk.opps.client.BasePayClient;
import com.huifu.bspay.sdk.opps.core.request.V2TradePaymentJspayRequest;
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
import com.hzs.common.core.enums.EPayBusinessType;
import com.hzs.common.core.enums.EPayStatus;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.StringUtils;
import com.hzs.common.core.web.domain.AjaxResult;
import com.hzs.common.domain.third.pay.TOnlinePayment;
import com.hzs.third.pay.config.HuiFuConfig;
import com.hzs.third.pay.constants.HuiFuPayConstants;
import com.hzs.third.pay.constants.PayRedisConstants;
import com.hzs.third.pay.dto.WechatPublicDTO;
import com.hzs.third.pay.dto.WechatStateDTO;
import com.hzs.third.pay.param.WechatCodeParam;
import com.hzs.third.pay.service.ITOnlinePaymentService;
import com.hzs.third.pay.util.PayUtil;
import com.hzs.third.pay.util.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * 汇付新支付控制器
 */
@Slf4j
@RestController
@RequestMapping("/huifu")
public class HuiFuPayController {

    @Autowired
    private HuiFuConfig huiFuConfig;
    @Autowired
    private ITOnlinePaymentService itOnlinePaymentService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 汇付下单
     *
     * @param param
     * @return
     */
    @PostMapping("/code-order")
    public AjaxResult codeOrder(@Valid @RequestBody WechatCodeParam param) {
        try {
            // 微信请求参数
            Map<String, Object> requestParam = new HashMap<>();
            requestParam.put("appid", huiFuConfig.getPublicAppId());
            requestParam.put("secret", huiFuConfig.getPublicAppSecret());
            requestParam.put("code", param.getCode());
            requestParam.put("grant_type", "authorization_code");

            // 根据code调用微信 oauth2.access_token 接口，获取用户 openId
            String resultStr = HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token", requestParam);
            if (StringUtils.isEmpty(resultStr)) {
                return AjaxResult.error("请求微信授权异常");
            }
            // 微信返回json转操作对象
            WechatPublicDTO wechatPublicDTO = JSONUtil.parseObj(resultStr).toBean(WechatPublicDTO.class);

            // 判断返回内容是否成功
            String errorMsg = WeChatUtil.handErrorCode(wechatPublicDTO.getErrcode());
            if (StringUtils.isNotEmpty(errorMsg)) {
                return AjaxResult.error(errorMsg);
            }
            // 用户公众号授权的 openId
            String openId = wechatPublicDTO.getOpenid();
            log.info("调用汇付新微信扫码支付前置微信授权! order: {}, openId: {}", param.getState(), openId);

            // redis 缓存KEY
            String stateKey = String.format(PayRedisConstants.HUIFU_STATE_KEY, param.getState());
            if (!redisTemplate.hasKey(stateKey)) {
                log.error("汇付新微信扫码支付失败，缓存订单已不存在");
                return AjaxResult.error("支付失败，请重新发起支付.");
            } else {
                Object payInfo = redisTemplate.opsForValue().get(stateKey);
                if (null == payInfo) {
                    log.error("汇付新微信扫码支付失败，缓存订单为空");
                    return AjaxResult.error("支付失败，请重新发起支付.");
                }
                // 缓存的支付信息
                WechatStateDTO wechatStateDTO = JSONUtil.toBean(payInfo.toString(), WechatStateDTO.class);

                // 支付类型
                int businessType = wechatStateDTO.getType();
                // 订单编号
                String orderCode = wechatStateDTO.getOrderCode();
                // 同一订单不能重复，此处添加随机数，防止多次调用
                String thirdOrderCode = PayUtil.getThirdOrderCode(orderCode, null);

                TOnlinePayment tOnlinePayment = itOnlinePaymentService.queryByBusiness(businessType, orderCode, null);
                if (null == tOnlinePayment) {
                    log.error("汇付新微信扫码支付失败，在线支付信息不存在");
                    return AjaxResult.error("支付失败，请重新发起支付!");
                }
                if (EPayStatus.PAID.getValue() == tOnlinePayment.getPayStatus()) {
                    // 在线支付信息已支付
                    log.error("汇付新微信扫码支付失败，在线支付信息已支付");
                    return AjaxResult.error("订单已支付");
                }

                // 实际支付金额
                BigDecimal amount = tOnlinePayment.getBusinessMoney();
                // 部分业务金额随机立减
                if (EPayBusinessType.getEnumByValue(businessType) == EPayBusinessType.RECHARGE
                        || EPayBusinessType.getEnumByValue(businessType) == EPayBusinessType.DIRECT_SELLING) {
                    // 充值、直销订单
                    amount = PayUtil.handleAmountRandom(tOnlinePayment.getBusinessMoney());
                }

                // 组装交易参数
                V2TradePaymentJspayRequest request = new V2TradePaymentJspayRequest();
                // 请求日期
                request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
                // 请求流水号（保证唯一）
                request.setReqSeqId(thirdOrderCode);
                // 商户id
                request.setHuifuId(huiFuConfig.getSysId());
                // 商品描述
                request.setGoodsDesc("支付：" + tOnlinePayment.getBusinessCode());
                // 交易类型（T_JSAPI：微信公众号支付，T_NATIVE：微信正扫，A_NATIVE：支付宝正扫）
                request.setTradeType("T_JSAPI");
                // 交易金额（单位元）
                DecimalFormat df = new DecimalFormat("#0.00");
                request.setTransAmt(df.format(amount.doubleValue()));

                Map<String, Object> extendInfoMap = new HashMap<>();
                // 该笔交易的异步通知地址（http/https异步通知地址，必须以virgo://开头）
                extendInfoMap.put("notify_url", huiFuConfig.getNotifyUrl());
                // 交易有效期（24小时）
                extendInfoMap.put("time_expire", DateTools.dateToDateString(DateUtils.addHours(tOnlinePayment.getModifiedTime(), 24), DateTools.DATE_TIME_YYYYMMDDHHMMSS));
                // 备注（交易后原样返回）
                extendInfoMap.put("remark", tOnlinePayment.getBusinessType().toString());
                // 微信相关信息
                JSONObject wxData = new JSONObject();
                wxData.putOpt("sub_appid", huiFuConfig.getPublicAppId());
                wxData.putOpt("sub_openid", openId);
                extendInfoMap.put("wx_data", wxData);
                // 扩展参数
                request.setExtendInfo(extendInfoMap);

                log.info("汇付新微信扫码支付调用参数：{}", request);

                Map<String, Object> response = BasePayClient.request(request);

                log.info("汇付新微信扫码支付调用返回：{}", response);

                // 获取返回内容
                JSONObject resultData = JSONUtil.parseObj(response.get("data"));

                if (HuiFuPayConstants.TRANS_SUCCESS.equals(resultData.getStr("trans_stat"))
                        || HuiFuPayConstants.TRANS_PROCESSING.equals(resultData.getStr("trans_stat"))) {
                    // 返回成功
                    // 微信支付数据
                    JSONObject payInfoResult = JSONUtil.parseObj(resultData.getStr("pay_info"));
                    return AjaxResult.success("", payInfoResult);
                } else {
                    log.error("汇付新微信扫码支付返回失败! resp_desc: {}, bank_message: {}, hf_seq_id: {}", response.get("resp_desc"), response.get("bank_message"), response.get("hf_seq_id"));
                    return AjaxResult.error("支付失败，请刷新后重试!");
                }
            }
        } catch (Exception e) {
            log.error("汇付新微信扫码支付处理返回异常!", e);
            return AjaxResult.error("支付异常，请返回刷新后重试");
        }
    }

}
