package com.sqx.modules.pay.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ekyong.www.pay.common.Constant;
import com.ekyong.www.pay.pay.qrcode.api.RhtQrcodePayApi;
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeOpenPayRequestBean;
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeOpenPayResponseBean;
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeRefundRequestBean;
import com.ekyong.www.pay.pay.qrcode.bean.QrcodeRefundResponseBean;
import com.ekyong.www.pay.pay.split.api.RhtSplitApi;
import com.ekyong.www.pay.pay.split.bean.SplitPayRequestBean;
import com.ekyong.www.pay.pay.split.bean.SplitPayResponseBean;
import com.ekyong.www.pay.util.SignUtil;
import com.sqx.common.exception.SqxException;
import com.sqx.common.utils.SpringContextUtils;
import com.sqx.modules.activity.service.ActivityPartRecordService;
import com.sqx.modules.activity.service.ActivityService;
import com.sqx.modules.address.entity.Address;
import com.sqx.modules.address.service.AddressService;
import com.sqx.modules.app.bo.UpdateMoneyBO;
import com.sqx.modules.app.dao.UserBrowseDao;
import com.sqx.modules.app.dao.UserDao;
import com.sqx.modules.app.dao.UserMoneyDao;
import com.sqx.modules.app.dao.UserMoneyDetailsDao;
import com.sqx.modules.app.service.UserMoneyService;
import com.sqx.modules.app.service.UserService;
import com.sqx.modules.common.service.CommonInfoService;
import com.sqx.modules.coupon.dao.TbCouponUserDao;
import com.sqx.modules.datacentre.service.DataCentreService;
import com.sqx.modules.errand.dao.TbIndentDao;
import com.sqx.modules.errand.service.TbIndentService;
import com.sqx.modules.errand.service.TbIndentSmsSendLogService;
import com.sqx.modules.errand.service.TbIndentSmsTemplateService;
import com.sqx.modules.goods.dao.GoodsDao;
import com.sqx.modules.goods.dao.GoodsShopDao;
import com.sqx.modules.goods.dao.GoodsShopRelevancyDao;
import com.sqx.modules.goods.dao.GoodsSkuDao;
import com.sqx.modules.goods.entity.GoodsShop;
import com.sqx.modules.goods.service.GoodsShopService;
import com.sqx.modules.integral.dao.UserIntegralDao;
import com.sqx.modules.integral.dao.UserIntegralDetailsDao;
import com.sqx.modules.message.dao.MessageInfoDao;
import com.sqx.modules.order.dao.AppOrderDao;
import com.sqx.modules.order.dao.EvaluateDao;
import com.sqx.modules.order.dao.OrderGoodsDao;
import com.sqx.modules.order.entity.OrderGoods;
import com.sqx.modules.order.entity.TbOrder;
import com.sqx.modules.order.service.AppOrderService;
import com.sqx.modules.order.service.EvaluateRiderService;
import com.sqx.modules.pay.config.WechatPayConfig;
import com.sqx.modules.pay.controller.app.AliPayController;
import com.sqx.modules.pay.dao.PayDetailsDao;
import com.sqx.modules.pay.dto.GetPayParamDTO;
import com.sqx.modules.pay.entity.PayDetails;
import com.sqx.modules.pay.enums.PayChannelEnum;
import com.sqx.modules.pay.enums.PaySceneEnum;
import com.sqx.modules.pay.enums.PayStateEnums;
import com.sqx.modules.pay.service.NewPayService;
import com.sqx.modules.pay.service.PayDetailsService;
import com.sqx.modules.pay.service.WxErrService;
import com.sqx.modules.pay.vo.WechatTransactionsParamVO;
import com.sqx.modules.shop.service.ShopMessageService;
import com.sqx.modules.shop.service.ShopTypeService;
import com.sqx.modules.sys.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class NewPayServiceImpl implements NewPayService {

    private final PayDetailsService payDetailsService;
    private final CommonInfoService commonInfoService;
    private final UserMoneyService userMoneyService;
    private final GoodsShopService goodsShopService;
    private final DataCentreService dataCentreService;

    /**
     * 润海通支付接口地址
     */
    private final static String RHT_PAY_BASE_URL = "https://api.ekbuyclub.com";

    private final static DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public WechatTransactionsParamVO getWechatTransactionsParamVO(GetPayParamDTO dto) {
        // 润海通支付，目前只测试了小程序支付，其余支付方式不考虑
        if (dto.getPayChannel() != PayChannelEnum.WECHAT_JS_API) {
            throw new SqxException("不支持的支付方式！");
        }

        PayDetails payDetails = payDetailsService.getByOrderNo(dto.getOrderNo());
        if (ObjectUtil.isNotNull(payDetails) && StrUtil.isNotBlank(payDetails.getRemark())) {
            // 如果在支付有效期内，则直接返回支付参数，否则提示订单超时
            LocalDateTime createTime = LocalDateTime.parse(payDetails.getCreateTime(), DTF);

            // 支付时间大于2小时后不能再次支付
            if (Duration.between(createTime, LocalDateTime.now()).toMinutes() > 120) {
                throw new SqxException("当前订单已超时关闭，请重新下单！");
            }

            if (BigDecimal.valueOf(payDetails.getMoney()).compareTo(dto.getAmount()) != 0) {
                throw new SqxException("支付金额检验失败，请清空购车后重试！");
            }

            return JSONUtil.toBean(payDetails.getRemark(), WechatTransactionsParamVO.class);
        }

        WechatPayConfig wechatMchConfig = getWechatMchConfig();
        RhtQrcodePayApi qrcodePay = new RhtQrcodePayApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);
        QrcodeOpenPayRequestBean openRequest = getQrcodeOpenPayRequestBean(dto, wechatMchConfig);

        WechatTransactionsParamVO wechatPayParamVO;
        try {
            QrcodeOpenPayResponseBean response = qrcodePay.openPay(openRequest);
            String barCode = response.getBarCode();
            if (StrUtil.isBlank(barCode)) {
                throw new SqxException(response.getMessage());
            }
            JSONObject barCodeJson = JSONUtil.parseObj(barCode);
            wechatPayParamVO = barCodeJson.toBean(WechatTransactionsParamVO.class);
            wechatPayParamVO.setPackageStr(barCodeJson.getStr("package"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new SqxException("获取支付参数失败：" + e.getMessage());
        }

        // 初始化支付订单
        payDetailsService.addPayDetail(dto, JSONUtil.toJsonStr(wechatPayParamVO));
        return wechatPayParamVO;
    }

    /**
     * 创建支付请求参数
     *
     * @param dto 包含支付参数的数据传输对象
     * @param wechatMchConfig 微信商户配置信息
     * @return 返回一个填充了支付信息的QrcodeOpenPayRequestBean对象
     */
    private QrcodeOpenPayRequestBean getQrcodeOpenPayRequestBean(GetPayParamDTO dto, WechatPayConfig wechatMchConfig) {
        String notifyUrl = wechatMchConfig.getH5Url() + "/sqx_fast/app/new-pay/wechat-pay/notify";

        QrcodeOpenPayRequestBean openRequest = new QrcodeOpenPayRequestBean();
        openRequest.setAmount(dto.getAmount().toString());
        openRequest.setTraceno(dto.getOrderNo());
        openRequest.setPayType(Constant.PAY_TYPE_WECHAT);
        openRequest.setGoodsName(dto.getOrderDesc());
        // 设置支付通知地址
        openRequest.setNotifyUrl(notifyUrl);
        // 小程序支付，固定填1
        openRequest.setCallType("1");
        openRequest.setAppid(wechatMchConfig.getAppId());
        openRequest.setOpenid(dto.getUserThirdId());

        return openRequest;
    }

    @Override
    public boolean wechatRefund(String orderNo) {
        WechatPayConfig wechatMchConfig = getWechatMchConfig();
        RhtQrcodePayApi qrcodePay = new RhtQrcodePayApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);
        QrcodeRefundRequestBean request = new QrcodeRefundRequestBean();
        // 商户流水号
        request.setTraceno(orderNo);
        // 接口版本号
        request.setVersion("1.0");

        try {
            QrcodeRefundResponseBean response = qrcodePay.refund(request);
            String respCode = response.getRespCode();
            if (StrUtil.equals("00", respCode)) {
                return true;
            } else {
                log.error("订单【{}】退款失败，失败原因：{}", orderNo, response.getMessage());
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SqxException("订单【" + orderNo + "】退款失败，失败原因：" + e.getMessage());
        }
    }

    @Override
    public void wechatSplitBill(String traceNo, String inMchId, BigDecimal amount) {
        WechatPayConfig wechatMchConfig = getWechatMchConfig();
        RhtSplitApi splitApi = new RhtSplitApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);

        String outAmount = amount.toString();

        SplitPayRequestBean request = new SplitPayRequestBean();
        request.setVersion("1.0");
        request.setTraceno(traceNo);
        request.setOutMerchno(wechatMchConfig.getMchId());
        request.setOutAmount(outAmount);

        SplitPayRequestBean.SplitDetail splitDetail = new SplitPayRequestBean.SplitDetail();
        splitDetail.setInAmount(outAmount);
        splitDetail.setInMerchno(inMchId);

        request.setSplitDetailList(JSONUtil.toJsonStr(Arrays.asList(splitDetail)));

        try {
            SplitPayResponseBean splitPayResponse = splitApi.splitPay(request);
            if (splitPayResponse.getStatus() != 1) {
                throw new SqxException("分账支付失败，" + splitPayResponse.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SqxException("分账，" + e.getMessage());
        }
    }

    @Override
    @Transactional
    public String wechatPayNotify(String reqJsonData) {
        try {
            String decode = URLDecoder.decode(reqJsonData, "GBK");
            Map<String, String> map = JSONUtil.toBean(decode, Map.class);
            log.info("收到rth支付通知，{}", JSONUtil.toJsonStr(map));

            // 微信商户key
            String mchKey = commonInfoService.findOne(435).getValue();
            boolean valid = SignUtil.validSignature(map, mchKey);
            if (!valid) {
                throw new SqxException("验签失败");
            }

            String status = map.get("status");
            String orderNo = map.get("traceno");
            String channelTraceNo = map.get("channelTraceno");
            String transDateStr = map.get("transDate");
            String transTime = map.get("transTime");
            if (StrUtil.equals(String.valueOf(PayStateEnums.PAY_SUCCESS.getStateCode()), status)) {
                PayDetails payDetails = payDetailsService.getByOrderNo(orderNo);
                if (ObjectUtil.isNull(payDetails)) {
                    log.error("订单【{}】支付成功，但未获取到支付订单！异步通知信息：{}", orderNo, reqJsonData);
                    return "success";
                }

                if (payDetails.getState() != PayStateEnums.WAIT_PAY.getStateCode()) {
                    // 支付订单不是未支付状态，直接返回
                    return "success";
                }

                payDetails.setState(PayStateEnums.PAY_SUCCESS.getStateCode());
                payDetails.setPayTime(transDateStr + " " + transTime);
                payDetails.setTradeNo(channelTraceNo);
                payDetails.setRemark("RHT PAY SUCCESS");
                payDetailsService.updateDetail(payDetails);

                PaySceneEnum payScene = PaySceneEnum.getBySceneCode(payDetails.getClassify());
                switch (payScene) {
                    case ORDER_PAY: handleTakeoutOrderPaySuccess(orderNo); break;
                    case BALANCE_RECHARGE: handleBalanceRechargePaySuccess(payDetails); break;
                    case BOND_PAY: handleBondPaySuccess(payDetails); break;
                    case VIP_PAY: handleVipPaySuccess(payDetails); break;
                    default:
                        log.error("监测到不支持的支付成功场景，支付订单信息：{}", JSONUtil.toJsonStr(payDetails));
                }
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异步通知处理异常：{}", e.getMessage());
            throw new SqxException("异步通知处理异常，" + e.getMessage());
        }
    }

    @Override
    public boolean enableNewPay() {
        String value = commonInfoService.findOne(433).getValue();
        return StrUtil.equals(value, "1");
    }

    /**
     * 处理vip购买成功通知
     * @param payDetails
     */
    private void handleVipPaySuccess(PayDetails payDetails) {
        dataCentreService.presenterVip(payDetails.getUserId());

        // 改动钱包明细？？
    }

    /**
     * 处理充值成功通知
     * @param payDetails
     */
    private void handleBalanceRechargePaySuccess(PayDetails payDetails) {
        UpdateMoneyBO updateMoneyBO = UpdateMoneyBO.builder()
                .userId(payDetails.getUserId())
                .type(1)
                .classify(3)
                .amount(new BigDecimal(payDetails.getMoney()))
                .title("充值入账")
                .remark(payDetails.getOrderId())
                .build();
        userMoneyService.updateUserMoney(updateMoneyBO);
    }

    /**
     * 处理充值成功通知
     * @param payDetails
     */
    private void handleBondPaySuccess(PayDetails payDetails) {
        goodsShopService.updateCashDeposit(payDetails.getMoney(), payDetails.getShopId(), payDetails.getOrderId());
    }

    /**
     * 处理外卖订单支付成功通知
     * @param orderNo 订单编号
     */
    private void handleTakeoutOrderPaySuccess(String orderNo) {
        AppOrderService appOrderService = SpringContextUtils.getBean(AppOrderService.class);

        // 根据订单编号查询订单
        TbOrder order = appOrderService.selectOrderByNum(orderNo);
        // 1 表示微信支付
        order.setPayType(1);
        // 订单支付成功，修改订单状态
        appOrderService.updateOrderAfterPaySuccess(order);
    }

    /**
     * 获取微信支付商户配置
     * @return 商户配置
     */
    private WechatPayConfig getWechatMchConfig() {
        return WechatPayConfig.builder()
                .appId(commonInfoService.findOne(45).getValue())
                .mchId(commonInfoService.findOne(434).getValue())
                .mchKey(commonInfoService.findOne(435).getValue())
                .h5Url(commonInfoService.findOne(19).getValue())
                .build();
    }
}
