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

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yonge.cooleshow.biz.dal.entity.UserOrder;
import com.yonge.cooleshow.biz.dal.entity.UserOrderPayment;
import com.yonge.cooleshow.biz.dal.entity.UserOrderRefundBill;
import com.yonge.cooleshow.common.entity.ContractDto;
import com.yonge.cooleshow.common.enums.CacheNameEnum;
import com.yonge.cooleshow.biz.dal.enums.OrderStatusEnum;
import com.yonge.cooleshow.biz.dal.service.UserOrderPaymentService;
import com.yonge.cooleshow.biz.dal.service.UserOrderRefundService;
import com.yonge.cooleshow.biz.dal.service.UserOrderService;
import com.yonge.toolset.payment.util.DistributedLock;
import com.yonge.cooleshow.biz.dal.vo.UserOrderVo;
import com.yonge.cooleshow.common.controller.BaseController;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.result.BaseResult;
import com.yonge.toolset.payment.base.enums.MethodNameEnum;
import com.yonge.toolset.payment.base.enums.OpenEnum;
import com.yonge.toolset.payment.base.enums.PayChannelEnum;
import com.yonge.toolset.payment.base.enums.PaymentClientEnum;
import com.yonge.toolset.payment.base.model.Payment;
import com.yonge.toolset.payment.base.model.callback.PaymentCallBack;
import com.yonge.toolset.payment.core.service.PaymentClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/open/userOrder")
@Api(value = "开放权限接口", tags = "开放权限接口")
public class UserOrderClient extends BaseController {
    private final static Logger log = LoggerFactory.getLogger(UserOrderClient.class);

    @Autowired
    private UserOrderPaymentService paymentService;
    @Autowired
    private UserOrderRefundService userOrderRefundService;
    @Autowired
    private UserOrderService userOrderService;
    @Autowired
    private PaymentClient paymentClient;
    @Autowired
    private RedissonClient redissonClient;

    @Value("${message.debugMode}")
    private boolean debugMode;

    @ApiOperation(value = "查询付款单")
    @GetMapping("/queryPayment")
    public HttpResponseResult<Payment> queryPayment(String paymentNo) {
        UserOrderPayment userOrderPayment = paymentService.getOne(Wrappers.<UserOrderPayment>lambdaQuery()
                .eq(UserOrderPayment::getPaymentNo, paymentNo)
        );
        if (null == userOrderPayment) {
            return HttpResponseResult.succeed();
        }
        Payment param = new Payment(userOrderPayment.getOpenType(),
                PaymentClientEnum.valueOf(userOrderPayment.getPaymentClient()), userOrderPayment.getPayChannel());
        param.setId(userOrderPayment.getTransNo());
        param.setPaymentNo(userOrderPayment.getPaymentNo());
        BaseResult<Payment> paymentBaseResult = paymentClient.queryPayment(param);
        return HttpResponseResult.status(paymentBaseResult);
    }

    /***
     * 支付回调
     * @author liweifan
     * @param: request
     * @updateTime 2022/3/11 18:35
     */
    @RequestMapping("/callback/{openType}/{client}/{payChannel}/{payMethod}")
    public Object callback(
            @PathVariable("openType") String openType,
            @PathVariable("client") String client,
            @PathVariable("payChannel") String payChannel,
            @PathVariable("payMethod") String payMethod,
            HttpServletRequest request
    ) {
        //支付回调：openType is ORIGINAL ,paymentClient is STUDENT，payChannel is ali_app，payMethod is executePayment
        log.info("支付回调：openType is {} ,paymentClient is {}，payChannel is {}，payMethod is {}", openType, client, payChannel, payMethod);
        BaseResult<PaymentCallBack> res = paymentClient.analysisNotice(
                OpenEnum.valueOf(openType), PaymentClientEnum.valueOf(client),
                PayChannelEnum.valueOf(payChannel), MethodNameEnum.valueOf(payMethod), request);
        log.info("统一解析结果：{}", JSONObject.toJSONString(res));

        if (res.getStatus()) {
            PaymentCallBack data = res.getData();
            //查询到订单
            UserOrderVo userOrderVo = userOrderService.getUserOrderByPaymentNoOrTransNo(data.getPaymentNo(), data.getId());
            if (null == userOrderVo) {
                return res.getData().getResMsg();
            }
            try {
                DistributedLock.of(redissonClient)
                        .runIfLockCanGet(CacheNameEnum.LOCK_EXECUTE_ORDER.getRedisKey(userOrderVo.getOrderNo())
                                , () -> {
                                    if (MethodNameEnum.executePayment.equals(data.getMethodName())) {
                                        //支付交易
                                        paymentService.executePaymentCallBack(data);
                                    } else if (MethodNameEnum.closePayment.equals(data.getMethodName())) {
                                        //关闭订单
                                        paymentService.closePaymentCallBack(data);
                                    } else if (MethodNameEnum.refundPayment.equals(data.getMethodName())) {
                                        //退款
                                        userOrderRefundService.refundPaymentCallBack(data);
                                    }
                                }, 60L, TimeUnit.SECONDS);
                return res.getData().getResMsg();
            } catch (BizException e) {
                log.error("回调业务异常，data is {}, msg is {}", JSONObject.toJSONString(data), e.getMessage());
            } catch (Exception e) {
                log.error("回调业务异常，data is {}", JSONObject.toJSONString(data));
                e.printStackTrace();
            }
        }
        return null;
    }

    /***
     * 支付回调
     * @author liweifan
     * @param: request
     * @updateTime 2022/3/11 18:35
     */
    @PostMapping("/testCallback")
    public void testCallback(@RequestBody PaymentCallBack data) {
        if (!debugMode) {
            return;
        }
        if (MethodNameEnum.executePayment.equals(data.getMethodName())) {
            //支付交易
            paymentService.executePaymentCallBack(data);
        } else if (MethodNameEnum.closePayment.equals(data.getMethodName())) {
            //关闭订单
            paymentService.closePaymentCallBack(data);
        } else if (MethodNameEnum.refundPayment.equals(data.getMethodName())) {
            //退款
            userOrderRefundService.refundPaymentCallBack(data);
        }
    }

    @GetMapping("/setSuccessStatus")
    @ApiOperation(value = "完成所有订单（测试用）")
    public HttpResponseResult<Boolean> setSuccessStatus() {
        if (!debugMode) {
            return HttpResponseResult.failed("当前环境不允许调用");
        }
        userOrderService.setSuccessStatus();
        return succeed(true);
    }

    @GetMapping("/setOrderStatus")
    @ApiOperation(value = "设置订单状态（测试用）")
    public HttpResponseResult<Boolean> setOrderStatus(
            @RequestParam("orderNo") String orderNo,
            @RequestParam("orderStatus") OrderStatusEnum orderStatus) {
        if (!debugMode) {
            return HttpResponseResult.failed("当前环境不允许调用");
        }

        UserOrder param = new UserOrder();
        param.setOrderNo(orderNo);
        param.setStatus(orderStatus);
        Boolean aBoolean = DistributedLock.of(redissonClient)
                .runIfLockToFunction(CacheNameEnum.LOCK_EXECUTE_ORDER.getRedisKey(orderNo)
                        , userOrderService::setOrderStatus, param, 10L);
        return succeed(aBoolean);
    }

    @GetMapping("/orderRefound")
    @ApiOperation(value = "退款（测试用）")
    public HttpResponseResult<UserOrderRefundBill> orderRefound(
            @RequestParam("orderNo") String orderNo) {
        if (!debugMode) {
            return HttpResponseResult.failed("当前环境不允许调用");
        }
        return userOrderRefundService.orderRefound(orderNo);
    }

    /**
     * 签协议 商城调用
     */
    @PostMapping("/contractRecord")
    @ApiOperation(value = "签协议 商城调用", notes = "签协议 商城调用")
    public HttpResponseResult<Boolean> contractRecord(@RequestBody ContractDto contract) {
        paymentService.setContractRecord(contract.getType(), contract.getUserId());
        return succeed(true);
    }
}
