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

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.huifu.adapay.model.Payment;
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.AdaPayConfig;
import com.hzs.third.pay.config.WeChatConfig;
import com.hzs.third.pay.constants.AdaPayConstants;
import com.hzs.third.pay.constants.PayRedisConstants;
import com.hzs.third.pay.controller.base.PayBaseController;
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 java.math.BigDecimal;
import java.net.InetAddress;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 汇付二维码支付控制器
 */
@Slf4j
@RestController
@RequestMapping("/ada-code")
public class AdaPayCodeController extends PayBaseController {

    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private AdaPayConfig adaPayConfig;
    @Autowired
    private ITOnlinePaymentService itOnlinePaymentService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 汇付下单
     *
     * @param param
     * @return
     */
    @PostMapping("/order")
    public AjaxResult order(@RequestBody WechatCodeParam param) {
        if (StringUtils.isAnyEmpty(param.getCode(), param.getState())) {
            return AjaxResult.error("缺少参数");
        }

        try {
            // 微信请求参数
            Map<String, Object> requestParam = new HashMap<>();
            requestParam.put("appid", weChatConfig.getPublicAppId());
            requestParam.put("secret", weChatConfig.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);
            // 测试使用
//            String openId = "ohLJU6P9Ivzq_6KeMU37yc6pyOxg";

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

                // 接口请求数据
                Map<String, Object> paymentParams = new HashMap<>();
                paymentParams.put("app_id", adaPayConfig.getAppId());
                paymentParams.put("order_no", thirdOrderCode);
                // 微信公众号支付
                paymentParams.put("pay_channel", "wx_pub");
                DecimalFormat df = new DecimalFormat("#0.00");
                // 支付金额
                paymentParams.put("pay_amt", df.format(amount.doubleValue()));
                paymentParams.put("goods_title", "支付：" + orderCode);
                paymentParams.put("goods_desc", "支付：" + orderCode);
                // 附加参数（成功回调原样返回）
                paymentParams.put("description", businessType);
                // 订单失效时间（1天）
                paymentParams.put("time_expire", DateUtils.parseDateTimeToStr(DateUtils.YAMMERERS, DateUtils.addDays(new Date(), 1)));
                // 前端设备信息
                Map<String, Object> deviceInfoMap = new HashMap<>();
                deviceInfoMap.put("device_ip", InetAddress.getLocalHost().getHostAddress());
                paymentParams.put("device_info", deviceInfoMap);
                // 支付渠道额外参数
                Map<String, Object> expendMap = new HashMap<>();
                expendMap.put("open_id", openId);
                paymentParams.put("expend", expendMap);
                paymentParams.put("notify_url", adaPayConfig.getCallbackUrl());

                log.info("汇付支付请求参数：{}", paymentParams);

                // 调用sdk方法，创建支付，得到支付对象
                Map<String, Object> resultData = Payment.create(paymentParams, adaPayConfig.getAppId());

                log.info("汇付支付返回参数：{}", resultData);

                if (AdaPayConstants.SUCCESS.equals(resultData.get("status"))) {
                    // 返回成功
                    // 支付渠道额外参数
                    Map<String, String> expendData = (Map<String, String>) resultData.get("expend");
                    // 微信支付数据
                    HashMap<String, String> payInfoMap = JSONUtil.toBean(expendData.get("pay_info"), HashMap.class);

                    return AjaxResult.success("", payInfoMap);
                } else {
                    log.error("调用汇付支付返回失败! code: {}, msg: {}, invalid_param: {}", resultData.get("error_code"), resultData.get("error_msg"), resultData.get("invalid_param"));
                    return AjaxResult.error("支付失败，请刷新后重试");
                }
            }
        } catch (Exception e) {
            log.error("调用汇付支付处理返回异常!", e);
            return AjaxResult.error("支付异常，请返回刷新后重试");
        }
    }

}
