package com.hzs.third.pay.service.impl;

import cn.hutool.json.JSONUtil;
import com.huifu.adapay.model.Payment;
import com.hzs.common.core.domain.R;
import com.hzs.common.core.enums.EBindStatus;
import com.hzs.common.core.text.CharsetKit;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.domain.third.pay.TOnlineCard;
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.dto.WechatStateDTO;
import com.hzs.third.pay.service.IAdaPayService;
import com.hzs.third.pay.service.ITOnlineCardService;
import com.hzs.third.pay.util.PayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 汇付支付服务
 * @Author: jiang chao
 * @Time: 2023/3/17 15:19
 * @Classname: AdaPayServiceImpl
 * @PackageName: com.hzs.third.pay.service.impl
 */
@Slf4j
@Service
public class AdaPayServiceImpl implements IAdaPayService {

    @Autowired
    private AdaPayConfig adaPayConfig;
    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private ITOnlineCardService itOnlineCardService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public R<String> createCode(TOnlinePayment onlinePayment) {
        try {
            if (onlinePayment.getPayMoney().compareTo(new BigDecimal("20000")) >= 0) {
                return R.fail("当前支付方式单笔金额不能超过20000");
            }

            // 缓存对象
            WechatStateDTO wechatStateDTO = new WechatStateDTO();
            wechatStateDTO.setType(onlinePayment.getBusinessType());
            wechatStateDTO.setOrderCode(onlinePayment.getBusinessCode());
            wechatStateDTO.setPkMember(onlinePayment.getPkModified());
            // redis 缓存KEY
            String stateKey = String.format(PayRedisConstants.ADA_STATE_KEY, onlinePayment.getBusinessCode());
            // 放到redis中缓存（有效期24小时）
            redisTemplate.opsForValue().set(stateKey, JSONUtil.toJsonStr(wechatStateDTO), 24, TimeUnit.HOURS);

            StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize");
            // 公众号appId
            url.append("?appid=").append(weChatConfig.getPublicAppId());
            // 重写向的URL -- https://new.hzs413.com/#/login
            url.append("&redirect_uri=").append(URLEncoder.encode(adaPayConfig.getRedirectUri(), CharsetKit.UTF_8));
            url.append("&response_type=code");
            // 默认授权，只拿openId
            url.append("&scope=snsapi_base");
            // 重定向后会带上 state 参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
            url.append("&state=").append(onlinePayment.getBusinessCode());
            url.append("#wechat_redirect");

            log.info("汇付生成公众号跳转URL：{}", url);

            return R.ok(url.toString());
        } catch (Exception e) {
            log.error("汇付扫码支付返回异常", e);
        }
        return R.fail("汇付扫码支付返回失败");
    }

    @Override
    public R<String> bankPay(TOnlinePayment onlinePayment, String bindCode) {
        try {
            // 查询用户绑卡信息
            TOnlineCard tOnlineCard = itOnlineCardService.queryCardByCode(bindCode, onlinePayment.getPkModified(), adaPayConfig.getAppId(), onlinePayment.getPkCountry());
            if (null == tOnlineCard || EBindStatus.BIND.getValue() != tOnlineCard.getBindStatus()) {
                return R.fail("用户未绑定该银行卡");
            }

            // 与三方对接，需要扩展支付订单号，用于标记业务
            String thirdOrderCode = PayUtil.getThirdOrderCode(onlinePayment.getBusinessCode(), null);
            onlinePayment.setOriginalOrder(thirdOrderCode);

            // 接口请求数据
            Map<String, Object> paymentParams = new HashMap<>();
            paymentParams.put("app_id", adaPayConfig.getAppId());
            paymentParams.put("order_no", thirdOrderCode);
            // 快捷支付
            paymentParams.put("pay_channel", "fast_pay");
            DecimalFormat df = new DecimalFormat("#0.00");
            paymentParams.put("pay_amt", df.format(onlinePayment.getPayMoney().doubleValue()));
            paymentParams.put("goods_title", "支付：" + onlinePayment.getBusinessCode());
            paymentParams.put("goods_desc", "支付：" + onlinePayment.getBusinessCode());
            // 附加参数（成功回调原样返回）
            paymentParams.put("description", onlinePayment.getBusinessType());
            // 订单失效时间（1天）
            paymentParams.put("time_expire", DateUtils.parseDateToFormat(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("token_no", tOnlineCard.getThirdInfo());
            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"))) {
                // 支付流水号
                onlinePayment.setPayNumber(resultData.get("id").toString());

                // 返回成功
                return R.ok();
            } else {
                log.error("调用汇付快捷预下单失败! code: {}, msg: {}, invalid_param: {}", resultData.get("error_code"), resultData.get("error_msg"), resultData.get("invalid_param"));
            }

        } catch (Exception e) {
            log.error("汇付银行卡下单异常!", e);
        }
        return R.fail("汇付银行卡下单返回失败");
    }

}
