package com.yonge.cooleshow.admin.controller.open;

import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huifu.adapay.core.AdapayCore;
import com.huifu.adapay.core.util.AdapaySign;
import com.microsvc.toolkit.common.response.template.R;
import com.microsvc.toolkit.common.webportal.exception.BizException;
import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
import com.microsvc.toolkit.middleware.payment.common.api.entity.RefundResp;
import com.microsvc.toolkit.middleware.payment.common.api.enums.PaymentStatus;
import com.yeepay.g3.sdk.yop.encrypt.DigitalEnvelopeDTO;
import com.yeepay.g3.sdk.yop.utils.DigitalEnvelopeUtils;
import com.yeepay.g3.sdk.yop.utils.RSAKeyUtils;
import com.yonge.cooleshow.biz.dal.entity.PaymentMerchantConfig;
import com.yonge.cooleshow.biz.dal.entity.TenantMember;
import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
import com.yonge.cooleshow.common.enums.EPayerType;
import com.yonge.cooleshow.common.enums.payment.EPaymentStatus;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.Objects;

@Slf4j
@RestController
@RequestMapping("${app-config.url.admin:}/open/userOrder")
@Api(tags = "开放权限接口-支付回调")
public class UserPaymentClient {

    @Autowired
    private PaymentServiceContext paymentServiceContext;
    @Autowired
    private UserPaymentCoreService userPaymentCoreService;
    @Autowired
    private UserPaymentOrderService userPaymentOrderService;

    @Autowired
    private UserOrderService userOrderService;

    @Autowired
    private TenantMemberService tenantMemberService;

    @Autowired
    private PaymentMerchantConfigService paymentMerchantConfigService;

    @Autowired
    private UserOrderRefundBillService userOrderRefundBillService;
    /**
     * 支付消息回调
     * @param request HttpServletRequest
     * @return String
     */
    @ApiOperation(value = "支付消息回调", notes = "三方支付平台支付消息通知")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
    })
    @RequestMapping(value = "/payment/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
    public String payment(@PathVariable("vendor") String vendor, HttpServletRequest request) {

        // 支付回调消息
        PaymentResp paymentResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForPay(request);
        if (Objects.isNull(paymentResp)) {
            return null;
        }
        log.info("payment vendor={}, paymentResp={}", vendor, JSON.toJSONString(paymentResp));
        // 支付订单确认
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService
                .getUserPaymentOrderByOrderNo( paymentResp.getMerOrderNo());
        if (Objects.isNull(paymentOrder)) {
            return paymentResp.getMsg();
        }

        // 执行支付回调流程
        userPaymentCoreService.executePaymentCallback(paymentResp);

        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
    }

    /**
     * 关闭订单测试
     * @param orderNo 订单号
     * @return R<UserPaymentOrderVo.UserPaymentOrder>
     */
    @ApiOperation(value = "关闭订单测试", notes = "关闭订单测试")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "orderNo", value = "订单号", dataType = "String")
    })
    @GetMapping("/closed/{orderNo}")
    public R<Object> testOrderClosed(@PathVariable("orderNo") String orderNo) {

        // 支付订单详情
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByOrderNo( orderNo);
        if (Objects.isNull(paymentOrder)) {
            throw BizException.from("订单不存在");
        }

        // 测试订单关闭
        PaymentResp paymentResp = userPaymentCoreService.closedPayment( paymentOrder);

        return R.from(paymentResp);
    }

    @ApiOperation(value = "关单消息回调", notes = "三方支付平台关单消息通知")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
    })
    @RequestMapping(value = "/closed/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
    public String closed(@PathVariable("vendor") String vendor, HttpServletRequest request) {

        // 支付回调消息
        PaymentResp paymentResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForClosed(request);
        // 关单回调对象为空或关闭失败，直接返回忽略后续流程
        if (Objects.isNull(paymentResp) || paymentResp.getPaymentStatus() != PaymentStatus.CLOSED) {
            return null;
        }
        log.info("closed vendor={}, paymentResp={}", vendor, JSON.toJSONString(paymentResp));

        // 支付订单确认
        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService.getUserPaymentOrderByTranNo(paymentResp.getTransNo());
        if (Objects.isNull(paymentOrder) || paymentOrder.getStatus() == EPaymentStatus.PAID || paymentOrder.getStatus() == EPaymentStatus.CLOSED) {
            return paymentResp.getMsg();
        }
        // 关单订单编号
        paymentResp.setMerOrderNo(paymentOrder.getOrderNo());

        // 执行支付回调流程
        userPaymentCoreService.executePaymentCallback(paymentResp);

        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
    }


    @ApiOperation(value = "用户付款", notes = "用户付款")
    @PostMapping("/executePayment/v2")
    public R<UserPaymentOrderWrapper.PaymentReq> executePayment(@Validated @RequestBody UserPaymentOrderWrapper.PaymentOrderReqConfig config,
                                                                HttpServletRequest request) {

        // 用户登录状态校验
        if (StringUtils.isBlank(config.getUserId())) {
            throw BizException.from("用户未登录");
        }

        // 用户下单请求
        UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig = UserPaymentOrderWrapper.PaymentOrderReqConfig.from(config.jsonString());

        // 支付三方
        reqConfig.setPaymentVendor(config.getPaymentVendor());
        // 请示IP地址
        reqConfig.setIp(ServletUtil.getClientIP(request));

        JwtUserInfo<Object> userInfo = JwtUserInfo.builder()
            .userId(config.getUserId())
            .clientType(config.getUserType().getCode())
            .build();
        // 创建用户支付数据
        UserPaymentOrderWrapper.PaymentReq paymentConfig = userPaymentCoreService.executePayment(userInfo, reqConfig);
        if (Objects.isNull(paymentConfig)) {
            throw BizException.from("用户支付请求错误");
        }

        return R.from(paymentConfig);
    }


    /**
     * 退款消息回调
     * @param request HttpServletRequest
     * @return String
     */
    @ApiOperation(value = "退款消息回调", notes = "三方支付平台退款消息通知")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
    })
    @RequestMapping(value = "/refund/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
    public String refund(@PathVariable("vendor") String vendor, HttpServletRequest request) {

        RefundResp refundResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForRefund(request);
        if (Objects.isNull(refundResp)) {
            log.info("refund REFUND_FAILED, vendor={}", vendor);
            return null;
        }
        log.info("refund vendor={}, refundResp={}", vendor, JSON.toJSONString(refundResp));

        // 执行退款回调流程
        userPaymentCoreService.refundPaymentCallback(refundResp);

        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
    }

    @PostMapping("/callback/adapay")
    public String callback(HttpServletRequest request) {
        log.info("adapay 子账户回调");
        try {
            // 验签请参data
            String data = request.getParameter("data");
            // 验签请参sign
            String sign = request.getParameter("sign");

            // 验签
            if (!AdapaySign.verifySign(data, sign, AdapayCore.PUBLIC_KEY)) {
                return "验签失败";
            }

            JSONObject dataObj = JSON.parseObject(data);
            log.info("adapay callback data:{}", dataObj.toJSONString());

            String memberId = dataObj.getString("member_id");

            TenantMember tenantMember = tenantMemberService.getByMemberId(memberId, EPayerType.ADAPAY);
            if(tenantMember == null){
                return "账户["+ memberId +"]在系统中不存在";
            }
            tenantMember.setUpdateTime(new Date());

            String transType = request.getParameter("type");

            switch (transType) {

                case "corp_member.succeeded":// 企业子账户开户成功
                    String settleAccountId = dataObj.getString("settle_account_id");
                    tenantMember.setSettleAccountId(settleAccountId);
                    tenantMember.setStatus(AuthStatusEnum.PASS);

                    break;

                case "corp_member.failed":// 企业子账户开户失败
                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
                    tenantMember.setMemo(dataObj.getString("audit_desc"));

                    break;

                case "corp_member_update.succeeded":// 更新企业用户对象成功
                    tenantMember.setStatus(AuthStatusEnum.PASS);

                    break;

                case "corp_member_update.failed":// 更新企业用户对象失败
                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
                    tenantMember.setMemo(dataObj.getString("audit_desc"));

                    break;

                default:
                    break;
            }

            tenantMemberService.updateById(tenantMember);

        } catch (Exception e) {
            return e.getMessage();
        }

        return "succeeded";
    }


    @PostMapping("/callback/yeepay/{requestNo}")
    public String callback(@PathVariable("requestNo") String requestNo, HttpServletRequest request) {

        log.info("yeepay 子账户回调");
        TenantMember tenantMember = tenantMemberService.getByRequestNo(requestNo);
        if(tenantMember == null){
            return "请求编号["+ requestNo +"]在系统中不存在";
        }
        tenantMember.setUpdateTime(new Date());

        PaymentMerchantConfig paymentMerchantConfig = paymentMerchantConfigService.getByPaymentVendor(tenantMember.getPayerName());
        if(paymentMerchantConfig == null){
            throw new BizException("机构[{}][{}]商户信息找不到", tenantMember.getTenantId(), EPayerType.YEEPAY.getCode());
        }

        try {

            String content = request.getParameter("response");

            // 构造结果通知请求对象
            DigitalEnvelopeDTO dto = new DigitalEnvelopeDTO();
            dto.setCipherText(content);
            PrivateKey privateKey = RSAKeyUtils.string2PrivateKey(paymentMerchantConfig.getRsaPrivateKey());
            PublicKey publicKey = RSAKeyUtils.string2PublicKey(paymentMerchantConfig.getRsaPublicKey());

            dto = DigitalEnvelopeUtils.decrypt(dto, privateKey, publicKey);

            log.info("易宝支付回调信息：response:{} plaintText:{}", content, dto.getPlainText());

            JSONObject dataObj = JSON.parseObject(dto.getPlainText());

            if("COMPLETED".equals(dataObj.getString("applicationStatus"))) {
                //审核成功
                tenantMember.setStatus(AuthStatusEnum.PASS);
                tenantMemberService.updateById(tenantMember);
            }else if("REVIEW_BACK".equals(dataObj.getString("applicationStatus"))) {
                //审核驳回
                tenantMember.setStatus(AuthStatusEnum.UNPASS);
                tenantMember.setMemo(dataObj.getString("auditOpinion"));
                tenantMemberService.updateById(tenantMember);
            }

            return "SUCCESS";
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @ApiOperation(value = "订单付款状态", notes = "订单付款状态")
    @PostMapping("/paymentStatus/{orderNo}")
    public R<Boolean> paymentStatus(@PathVariable("orderNo") String orderNo) {


        // 用户订单支付状态

        userPaymentCoreService.paymentStatus(orderNo);

        return R.from(false);
    }
}
