package cn.quant.baa.pay.rest;

import cn.quant.baa.pay.acquirer.AcquirerProperties;
import cn.quant.baa.pay.acquirer.AcquirerPropertiesSource;
import cn.quant.baa.pay.acquirer.ChannelRequest;
import cn.quant.baa.pay.acquirer.ChannelResponse;
import cn.quant.baa.pay.annotation.BusinessMapping;
import cn.quant.baa.pay.model.BusinessRequest;
import cn.quant.baa.pay.model.web.*;
import cn.quant.baa.pay.service.TransactionService;
import cn.quant.baa.pay.util.AssertUtils;
import cn.quant.spring.http.HttpResponseData;
import cn.quant.spring.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import static cn.quant.baa.pay.Constant.PAY_DUE_TIME;
import static cn.quant.baa.pay.Constant.REDIS_NAMESPACE_PAY;
import static cn.quant.baa.pay.dict.MessageEnum.*;

/**
 * Created by Administrator on 2021/8/24 0024.
 */
@RestController
@RequestMapping("/transaction")
public class TransactionController extends BusinessController {

    @Autowired
    private TransactionService transactionService;

    @Autowired
    private AcquirerPropertiesSource acquirerPropertiesSource;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    public AcquirerProperties check(ChannelRequest data) {
        if (data == null) {
            AssertUtils.throwMessage(ILLEGAL_REQ_DATA);
        }
        String chanId = data.getChanId();
        if (chanId == null) {
            AssertUtils.throwMessage(ILLEGAL_REQ_CHAN_ID, chanId);
        }

        AcquirerProperties properties = acquirerPropertiesSource.get(Long.valueOf(chanId));
        if (properties == null) {
            AssertUtils.throwMessage(ACQUIRER_NOSUCH, chanId);
        }

        return properties;
    }


    @ResponseBody
    @BusinessMapping(session = 1)
    @PostMapping("/pay")
    public ResponseEntity pay(@RequestBody BusinessRequest<PayRequestData> request) throws Exception {
        PayRequestData requestData = request.getData();
        AcquirerProperties properties = check(requestData);
        String institutionId = properties.getInstitutionId();
        String productId = properties.getProductId();
        String outTradeNo = requestData.getOutTradeNo();
        String redisKey = StringUtils.toDelimitedString(REDIS_NAMESPACE_PAY, institutionId, productId, outTradeNo);
        String redisValue = stringRedisTemplate.opsForValue().get(redisKey);
        if (redisValue != null) {
            return ResponseEntity.ok(deserialize(redisValue));
        }
        ChannelResponse channelResponse = transactionService.pay(properties, requestData);
        HttpResponseData response = response(channelResponse);
        if (channelResponse.getSuccess()) {
            stringRedisTemplate.opsForValue().set(redisKey, serialize(response), PAY_DUE_TIME);
        }
        return ResponseEntity.ok(response);
    }

    @ResponseBody
    @BusinessMapping(session = 1)
    @PostMapping("/checkPay")
    public ChannelResponse checkPay(@RequestBody BusinessRequest<CheckPayRequestData> request) throws Exception {

        CheckPayRequestData data = request.getData();
        ChannelResponse responseData = null;

        responseData = transactionService.checkPay(data);


        System.currentTimeMillis();
        return responseData;
    }

    @ResponseBody
    @BusinessMapping(session = 1)
    @PostMapping("/checkRefund")
    public ChannelResponse checkRefund(@RequestBody BusinessRequest<CheckRefundRequestData> request) throws Exception {

        CheckRefundRequestData data = request.getData();
        ChannelResponse responseData = null;

        responseData = transactionService.checkRefund(data);


        System.currentTimeMillis();
        return responseData;
    }

    @ResponseBody
    @BusinessMapping(session = 1)
    @PostMapping("/close")
    public ChannelResponse close(@RequestBody BusinessRequest<CloseRequestData> request) throws Exception {

        CloseRequestData data = request.getData();
        ChannelResponse responseData = null;

        responseData = transactionService.close(data);


        System.currentTimeMillis();
        return responseData;
    }

    @ResponseBody
    @BusinessMapping(session = 1)
    @PostMapping("/refund")
    public ChannelResponse refund(@RequestBody BusinessRequest<RefundRequestData> request) throws Exception {

        RefundRequestData data = request.getData();
        ChannelResponse responseData = null;

        responseData = transactionService.refund(data);


        System.currentTimeMillis();
        return responseData;
    }

}
