package com.iformall.controller;


import com.iformall.common.ErrorCode;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxCouponOrderCVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.service.*;
import com.iformall.utils.IPUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Stormeye Wu wuguoqiang@iformall.com
 */
@RestController
@Api(description = "刷卡支付")
@RequestMapping("/api/micropay")
public class WxMicroPayController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxMerchantBUserService wxMerchantBUserService;

    @Autowired
    WxMerchantService wxMerchantService;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxPayOrderService wxPayOrderService;

    @Autowired
    WxRefundOrderService wxRefundOrderService;

    @Autowired
    WxAppinfoService wxAppinfoService;

    @Autowired
    WxCouponOrderService wxCouponOrderService;

    @Autowired
    private WxCUserBasicInfoService wxCUserBasicInfoService;

    @Autowired
    private WxCUserService wxCUserService;

    @Autowired
    private PosCouponOrderVerifyService posCouponOrderVerifyService;

    @ApiOperation(value = "付款码支付订单", notes = "params:{\"authCode\":\"String\",\"totalFee\":\"支付金额\"},\n" +
            "注意:\n" +
            "提醒1：提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时，商户系统等待5秒后调用【查询订单API】，查询支付实际交易结果；当返回结果为“USERPAYING”时，商户系统可设置间隔时间(建议10秒)重新查询支付结果，直到支付成功或超时(建议30秒)；\n" +
            "提醒2：在调用查询接口返回后，如果交易状况不明晰，请调用【撤销订单API】，此时如果交易失败则关闭订单，该单不能再支付成功；如果交易成功，则将扣款退回到用户账户。当撤销无返回或错误时，请再次调用。注意：请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。")
    @PostMapping("order_create")
    public ResultData saveMicopayOrder(@RequestBody Map<String, String> paramMap, HttpServletRequest request) {
        logger.info("saveMicopayOrder: " + paramMap.toString());
        //Assert.notNull(wxOrders.getName(), "角色名不能为空");
        //Assert.isTrue(!checkUnique(sysRole.getName(), null), "重复的角色名");
        String authCode = paramMap.get("authCode");
        String totalFeeStr = paramMap.get("totalFee");

        if (StringUtils.isBlank(authCode)) {
            logger.error("authCode不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "authCode不能为空");
        }
        if (StringUtils.isBlank(totalFeeStr)) {
            logger.error("totalFee不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "totalFee不能为空");
        }

        String ipStr = IPUtil.getIpAddr(request);

        WxMerchantBUser user = getUser();

        WxOrder order = null;
        try {
            order = wxOrderService.saveMicroPayOrder(user, totalFeeStr);
        } catch (MallinkException e) {
            logger.error("saveMicopayOrder 1" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("saveMicopayOrder 2" + e.getMessage());
            return new ResultData(ErrorCode.ORDER_IS_FAIL, e.getMessage());
        }

        WxPayOrder record = new WxPayOrder();
        record.setTenantId(user.getTenantId());
        record.setOrderId(order.getId());
        record.setAuthCode(authCode);
        record.setPayAmount(order.getPayment());
        record.setIp(ipStr);

        try {
            return wxPayOrderService.createMicroPayOrder(user, record, EnumPayWay.PAY_WAY_WECHAT);
        } catch (MallinkException e) {
            logger.error("payment wechat, order create error, req 2: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("payment wechat, order create error, req 3: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(ErrorCode.PAY_ORDER_ERROR, e.getMessage());
        }
    }

    @ApiOperation(value = "付款码支付订单v2", notes = "params:{\"payPrice\":\"总支付金额\",\"cUserId\":\"会员ID\"},\n" +
            "注意:\n" +
            "提醒1：提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时，商户系统等待5秒后调用【查询订单API】，查询支付实际交易结果；当返回结果为“USERPAYING”时，商户系统可设置间隔时间(建议10秒)重新查询支付结果，直到支付成功或超时(建议30秒)；\n" +
            "提醒2：在调用查询接口返回后，如果交易状况不明晰，请调用【撤销订单API】，此时如果交易失败则关闭订单，该单不能再支付成功；如果交易成功，则将扣款退回到用户账户。当撤销无返回或错误时，请再次调用。注意：请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。")
    @PostMapping("order_create_v2")
    public ResultData saveMicopayOrderV2(@RequestBody Map<String, String> paramMap, HttpServletRequest request) {
        logger.info("saveMicopayOrderV2: " + paramMap.toString());
        WxMerchantBUser user = getUser();
        String cUserIdStr = paramMap.get("cUserId");
        String payPriceStr = paramMap.get("payPrice");
        if (StringUtils.isBlank(cUserIdStr)) {
            logger.error("cUserId不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        if (StringUtils.isBlank(payPriceStr)) {
            logger.error("payPriceStr不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }

        Long cUserId = 0L;
        try {
            cUserId = Long.valueOf(cUserIdStr);
        } catch (NumberFormatException e) {
            cUserId = 0L;
            logger.error("cUserId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_CLASSCAST_ERROR);
        }

        WxCUser cUser = wxCUserService.getById(Long.valueOf(cUserIdStr));
        if (cUser == null) {
            logger.error("cUser不存在: " + cUserIdStr);
            return new ResultData(ErrorCode.USER_IS_EMPTY);
        }

        String ipStr = IPUtil.getIpAddr(request);

        BigDecimal payPrice = new BigDecimal(payPriceStr);
        payPrice.setScale(2, BigDecimal.ROUND_HALF_UP); // 第一个变量是小数位数，第二个变量是取舍方法(四舍五入)

        int payment = payPrice.multiply(new BigDecimal(100)).intValue();

        WxOrder order = null;
        try {
            order = wxOrderService.saveMicroPayOrderV2(user, cUser, payment);
        } catch (MallinkException e) {
            logger.error("saveMicopayOrder 1" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("saveMicopayOrder 2" + e.getMessage());
            return new ResultData(ErrorCode.ORDER_IS_FAIL, e.getMessage());
        }

        List<WxCouponOrderCVo> avaList = wxCouponOrderService.queryMicroPayCouponOrder(user, cUser, payment);
        Map retMap = new HashMap();
        if (order != null) {
            retMap.put("order", order);
        }
        if (avaList.size() > 0) {
            retMap.put("avaList", avaList);
        }
        return new ResultData(retMap);
    }

    @ApiOperation(value = "付款码支付订单", notes = "params:{\"orderId\":\"订单\",\"authCode\":\"String\",\"payment\":\"支付金额\"},\n" +
            "注意:\n" +
            "提醒1：提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时，商户系统等待5秒后调用【查询订单API】，查询支付实际交易结果；当返回结果为“USERPAYING”时，商户系统可设置间隔时间(建议10秒)重新查询支付结果，直到支付成功或超时(建议30秒)；\n" +
            "提醒2：在调用查询接口返回后，如果交易状况不明晰，请调用【撤销订单API】，此时如果交易失败则关闭订单，该单不能再支付成功；如果交易成功，则将扣款退回到用户账户。当撤销无返回或错误时，请再次调用。注意：请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。")
    @PostMapping("pay_order_create_v2")
    public ResultData saveMicopayPayOrder(@RequestBody Map<String, String> paramMap, HttpServletRequest request) {
        logger.info("saveMicopayPayOrder: " + paramMap.toString());
        WxMerchantBUser user = getUser();
        String orderIdStr = paramMap.get("orderId");
        String authCode = paramMap.get("authCode");
        String paymentStr = paramMap.get("payment");

        if (StringUtils.isBlank(orderIdStr)) {
            logger.error("orderId不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空");
        }
        if (StringUtils.isBlank(authCode)) {
            logger.error("authCode不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "authCode不能为空");
        }
        if (StringUtils.isBlank(paymentStr)) {
            logger.error("payment不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "payment不能为空");
        }

        String ipStr = IPUtil.getIpAddr(request);

        WxOrder order = wxOrderService.getById(Long.valueOf(orderIdStr));
        if (order == null) {
            logger.error("订单未找到" + orderIdStr);
            return new ResultData(ErrorCode.ORDER_IS_FAIL);
        }

        WxPayOrder record = new WxPayOrder();
        record.setTenantId(user.getTenantId());
        record.setOrderId(order.getId());
        record.setAuthCode(authCode);
        record.setPayAmount(Integer.valueOf(paymentStr));
        record.setIp(ipStr);

        try {
            return wxPayOrderService.createMicroPayOrder(user, record, EnumPayWay.PAY_WAY_WECHAT);
        } catch (MallinkException e) {
            logger.error("payment wechat, order create error, req 2: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("payment wechat, order create error, req 3: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(ErrorCode.PAY_ORDER_ERROR, e.getMessage());
        }
    }

    @ApiOperation(value = "查询付款码支付订单", notes = "{\"payOrderId\":\"String\",\"orderId\":\"String\"}")
    @PostMapping("order_query")
    public ResultData queryMicopayOrder(@RequestBody Map<String, String> paramMap) {
        logger.info("queryMicopayOrder: " + paramMap.toString());
        String payOrderIdStr = paramMap.get("payOrderId");
        String orderIdStr = paramMap.get("orderId");

        if (StringUtils.isBlank(payOrderIdStr)) {
            logger.error("payOrderId不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "payOrderId不能为空");
        }
        if (StringUtils.isBlank(orderIdStr)) {
            logger.error("orderId不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空");
        }
        WxMerchantBUser user = getUser();

        Long payOrderId = 0L;
        Long orderId = 0L;
        try {
            payOrderId = Long.valueOf(payOrderIdStr);
        } catch (NumberFormatException e) {
            payOrderId = 0L;
            logger.error("payOrderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        try {
            orderId = Long.valueOf(orderIdStr);
        } catch (NumberFormatException e) {
            orderId = 0L;
            logger.error("orderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }

        WxPayOrder record = new WxPayOrder();
        record.setTenantId(user.getTenantId());
        record.setId(payOrderId);
        record.setBUserId(user.getId());
        record.setOrderId(orderId);

        try {
            ResultData resultData = wxPayOrderService.payOrderQuery(record);
            return resultData;
        } catch (MallinkException e) {
            logger.error("payment wechat, order query error, req 2: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("payment wechat, order query error, req 3: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(ErrorCode.PAY_ORDER_QUERY_ERROR, e.getMessage());
        }
    }

    @ApiOperation(value = "撤销付款码支付订单", notes = "{\"payOrderId\":\"String\",\"orderId\":\"String\"}")
    @PostMapping("order_reverse")
    public ResultData reverseMicopayOrder(@RequestBody Map<String, String> paramMap) {
        logger.info("reverseMicopayOrder: " + paramMap.toString());
        String payOrderIdStr = paramMap.get("payOrderId");
        String orderIdStr = paramMap.get("orderId");

        if (StringUtils.isBlank(payOrderIdStr)) {
            logger.error("payOrderId不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "payOrderId不能为空");
        }
        if (StringUtils.isBlank(orderIdStr)) {
            logger.error("orderId不能为空");
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "orderId不能为空");
        }

        Long payOrderId = 0L;
        Long orderId = 0L;
        try {
            payOrderId = Long.valueOf(payOrderIdStr);
        } catch (NumberFormatException e) {
            payOrderId = 0L;
            logger.error("payOrderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        try {
            orderId = Long.valueOf(orderIdStr);
        } catch (NumberFormatException e) {
            orderId = 0L;
            logger.error("orderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }

        WxPayOrder record = new WxPayOrder();
        record.setTenantId(getTenantId());
        record.setId(payOrderId);
        record.setPayOrderNo(payOrderIdStr);
        record.setBUserId(getUser().getId());
        record.setOrderId(orderId);

        try {
            return wxPayOrderService.payOrderReverse(record);
        } catch (MallinkException e) {
            logger.error("payment wechat, order query error, req 2: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("payment wechat, order query error, req 3: " + record.toString() + ", e:" + e.getMessage());
            return new ResultData(ErrorCode.PAY_ORDER_ERROR, e.getMessage());
        }
    }

    @ApiOperation("付款码支付交易流水分页列表接口")
    @GetMapping("listMicroPay")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期yyyy-MM-dd", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query",required = true),
            @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query",required = true)})
    public ResultData listMicroPay(String date, Integer pageNum, Integer pageSize) {
        return wxOrderService.microPayListOnDateAsPage(getUser().getId(), EnumOrderType.MICROPAY.getCode(), date, pageNum, pageSize);
    }

    @ApiOperation("付款码支付某日期交易总流水")
    @GetMapping("getMicroPayAmountOnDate")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期yyyy-MM-dd", dataType = "string", paramType = "query")})
    public ResultData getMicroPayAmountOnDate(String date) {
        return wxOrderService.microPayListOnDateAsPage(getUser().getId(), EnumOrderType.MICROPAY.getCode(), date, null, null);
    }


    @ApiOperation(value = "付款码支付退款", notes = "{\"orderId\":\"string\"}")
    @PostMapping("/microPayRefund")
    public ResultData create(@RequestBody Map<String, String> paramMap) {
        //Assert.notNull(wxRefundOrder.getName(), "角色名不能为空");
        //Assert.isTrue(!checkUnique(sysRole.getName(), null), "重复的角色名");
        logger.info(paramMap.toString());
        String orderIdStr = paramMap.get("orderId");
        if (StringUtils.isBlank(orderIdStr)) {
            logger.error("orderId不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        Long orderId = 0L;
        try {
            orderId = Long.valueOf(orderIdStr);
        } catch (NumberFormatException e) {
            logger.error("orderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }

        WxMerchantBUser bUser = getUser();
        WxAppinfo appinfo = getAppInfo(bUser.getAppId());
        try {
            ResultData rd = wxRefundOrderService.createRefundOrderFromMicroPay(appinfo, orderId, EnumPayType.PAY_B_REFUND, bUser.getId());
            return rd;
        } catch (MallinkException e) {
            logger.error("退款 1：" + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("退款 2：" + e.getMessage());
            return new ResultData(ErrorCode.REFUND_ORDER_ERROR);
        }
    }

    @ApiOperation(value = "收银台核销券", notes = "{\"orderId\":\"必填\",\"couponOrderId\":\"必填\",\"payPrice\":\"支付金额(分)\"}")
    @PostMapping("userCouponOrderForMicroPay")
    public ResultData userCouponOrderForMicroPay(@RequestBody Map<String, String> paramMap) {
        logger.info("couponOrderController.verify:"+paramMap.toString());
        String orderIdStr = paramMap.get("orderId");
        String couponOrderIdStr = paramMap.get("couponOrderId");
        String payPriceStr = paramMap.get("payPrice");
        if (StringUtils.isBlank(orderIdStr)) {
            logger.error("orderId不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        if (StringUtils.isBlank(couponOrderIdStr)) {
            logger.error("couponOrderId不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        if (StringUtils.isBlank(payPriceStr)) {
            logger.error("payPrice不能为空: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }
        Long couponOrderId = 0L, orderId = 0L;
        BigDecimal totalFee = new BigDecimal(payPriceStr);
        totalFee.setScale(2, BigDecimal.ROUND_HALF_UP); // 第一个变量是小数位数，第二个变量是取舍方法(四舍五入)
        Integer payPrice = totalFee.multiply(new BigDecimal(100)).intValue();
        try {
            couponOrderId = Long.valueOf(couponOrderIdStr);
            orderId = Long.valueOf(orderIdStr);
        } catch (NumberFormatException e) {
            couponOrderId = 0L;
            orderId = 0L;
            logger.error("couponOrderId参数不正确: " + paramMap.toString());
            return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
        }

        WxOrder microOrder = wxOrderService.getById(orderId);
        if (microOrder == null) {
            return new ResultData(ErrorCode.ORDER_IS_NOT_FIND);
        }

        WxCouponOrderCVo wxCouponOrderCVo = wxCouponOrderService.detailCUserVo(couponOrderIdStr);
        if (wxCouponOrderCVo == null) {
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }

        WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoService.getById(wxCouponOrderCVo.getcUserId());
        if (wxCUserBasicInfo != null && EnumCreditLockedStatus.CLOSE.getCode().equals(wxCUserBasicInfo.getStatus())) {
            return new ResultData(ErrorCode.MEMBER_IS_LOCKED);
        }

        if (wxCouponOrderCVo.getValidStartDate() != null && wxCouponOrderCVo.getValidEndDate() != null ) {
            Date now = new Date();
            if (wxCouponOrderCVo.getValidStartDate().getTime() > now.getTime()) {
                logger.error("此券有效期未开始:" + couponOrderIdStr);
                return new ResultData(ErrorCode.COUPON_ORDER_IS_EARLIER_THAN_VALIDDATE);
            }
            if (wxCouponOrderCVo.getValidEndDate().getTime() < now.getTime()) {
                logger.error("此券有效期已结束:" + couponOrderIdStr);
                return new ResultData(ErrorCode.COUPON_ORDER_IS_LATER_THAN_VALIDDATE);
            }
        }

        WxCouponOrder wxCouponOrder = wxCouponOrderService.getById(couponOrderId);
        if (wxCouponOrder == null) {
            logger.error("券ID不存在:" + couponOrderId);
            return new ResultData(ErrorCode.COUPON_ORDER_IS_NULL);
        }

        WxMerchantBUser wxMerchantBUser = wxMerchantBUserService.getById(getUser().getId());
        if (wxMerchantBUser == null) {
            logger.error("核销员ID不存在:" + getUser().getId());
            throw new MallinkException(ErrorCode.USER_IS_EMPTY.getCode(), "核销员ID不存在或者无权限");
        }
        wxMerchantBUser.setBuserId(getBuserId());



        WxCouponOrder couponOrder = null;
        Integer remainPrice = payPrice;
        try {
            remainPrice = wxCouponOrderService.microPayVerify(microOrder, wxCouponOrder, wxMerchantBUser, payPrice);
        } catch (MallinkException e) {
            logger.error("核销异常: " + e.getMessage());
            return new ResultData(e.getErrorCode(), e.getMessage());
        } catch (Exception e) {
            logger.error("核销异常: " + e.getMessage());
            return new ResultData(ErrorCode.VERIFY_ERROR, e.getMessage());
        }

        if(couponOrder != null) {
            wxCouponOrderService.sendInsideCouponVerifyMsg(couponOrder.getTenantId(), couponOrderId, wxMerchantBUser.getId());
        }
        Double remainPriceD = Double.valueOf(remainPrice);
        String remainPriceStr = String.format("%.2f", remainPriceD);

        return new ResultData(remainPrice);
    }
}
