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

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.hzs.common.core.enums.EPayBusinessType;
import com.hzs.common.core.enums.EPayStatus;
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.AllInPayConfig;
import com.hzs.third.pay.constants.AllInPayConstants;
import com.hzs.third.pay.constants.PayRedisConstants;
import com.hzs.third.pay.dto.WechatStateDTO;
import com.hzs.third.pay.param.WechatCodeParam;
import com.hzs.third.pay.service.IAllInPayService;
import com.hzs.third.pay.service.ITOnlinePaymentService;
import com.hzs.third.pay.util.AllInPayUtil;
import com.hzs.third.pay.util.PayUtil;
import com.hzs.third.pay.util.WeChatUtil;
import com.hzs.third.wechat.dto.WeChatCodeDTO;
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 java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 通联二维码支付控制器
 */
@Slf4j
@RestController
@RequestMapping("/all-in-code")
public class AllInPayCodeController {

    @Autowired
    private AllInPayConfig allInPayConfig;
    @Autowired
    private ITOnlinePaymentService itOnlinePaymentService;
    @Autowired
    private IAllInPayService iAllInPayService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 通联下单（小程序）
     *
     * @param param
     * @return
     */
    @PostMapping("/applet-order")
    public AjaxResult appletOrder(@RequestBody WechatCodeParam param) {
        if (StringUtils.isAnyEmpty(param.getCode(), param.getState())) {
            return AjaxResult.error("缺少参数");
        }

        try {
            // 微信请求参数
            Map<String, Object> requestParam = new HashMap<>();
            requestParam.put("appid", allInPayConfig.getAppletPayAppId());
            requestParam.put("secret", allInPayConfig.getAppletPaySecret());
            requestParam.put("js_code", param.getCode());
            requestParam.put("grant_type", "authorization_code");

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

            // 判断返回内容是否成功
            String errorMsg = WeChatUtil.handErrorCode(weChatCodeDTO.getErrcode());
            if (StringUtils.isNotEmpty(errorMsg)) {
                return AjaxResult.error(errorMsg);
            }

            // 用户小程序授权的 openId
            String openId = weChatCodeDTO.getOpenid();
            log.info("调用通联前置微信授权! order: {}, openId: {}", param.getState(), openId);

            // redis 缓存KEY
            String stateKey = String.format(PayRedisConstants.ALLIN_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, businessType);

                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());
                }

                TreeMap<String, String> params = new TreeMap<>();
                params.put("appid", allInPayConfig.getAppId());
                params.put("cusid", allInPayConfig.getCustomerNum());
                params.put("randomstr", System.currentTimeMillis() + "");
                params.put("signtype", AllInPayConstants.SIGN_TYPE);
                params.put("version", AllInPayConstants.VERSION);

                // 交易金额（分）
                params.put("trxamt", amount.multiply(new BigDecimal("100")).intValue() + "");
                // 商户交易单号
                params.put("reqsn", thirdOrderCode);
                // 交易方式
                params.put("paytype", AllInPayConstants.WX_APPLET);
                // 订单标题
                params.put("body", "支付：" + orderCode);
                // 有效时间（分钟）
                params.put("validtime", "1440");
                // 小程序appId
                params.put("sub_appid", allInPayConfig.getAppletPayAppId());
                // 小程序用户openid
                params.put("acct", openId);
                // 回调地址
                params.put("notify_url", allInPayConfig.getCallbackUrl());

                // 签名
                params.put("sign", AllInPayUtil.unionSign(params, allInPayConfig.getPrivateKey(), AllInPayConstants.SIGN_TYPE));

                log.info("通联微信支付请求参数：{}", params);

                // 请求接口返回内容
                Map<String, String> resultMap = iAllInPayService.doRequest(allInPayConfig.getRequestUrl() + "/unitorder/pay", params);

                if (AllInPayConstants.SUCCESS_CODE.equals(resultMap.get("trxstatus"))) {
                    // 返回成功
                    // 前端使用支付参数
                    Map<String, String> payDataMap = JSONUtil.toBean(resultMap.get("payinfo"), HashMap.class);

                    // 微信支付数据
                    return AjaxResult.success(payDataMap);
                } else {
                    log.error("调用通联支付返回失败：{}", resultMap.get("returnMsg"));
                    return AjaxResult.error("支付失败，请刷新后重试");
                }
            }
        } catch (Exception e) {
            log.error("调用通联支付处理返回异常!", e);
            return AjaxResult.error("支付异常，请返回刷新后重试");
        }
    }

}
