package com.liquidnet.service.adam.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.github.pagehelper.PageInfo;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liquidnet.common.cache.redisson.util.RedisLockUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.ServletUtils;
import com.liquidnet.service.adam.dto.AdamMemberOrderCallbackParam;
import com.liquidnet.service.adam.dto.AdamMemberOrderCodeParam;
import com.liquidnet.service.adam.dto.AdamMemberOrderParam;
import com.liquidnet.service.adam.dto.AdamMemberOrderResult;
import com.liquidnet.service.adam.dto.vo.*;
import com.liquidnet.service.adam.service.IAdamMemberOrderService;
import com.liquidnet.service.adam.service.IAdamRdmService;
import com.liquidnet.service.adam.service.IAdamUserService;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
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.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

import java.util.List;

import static com.liquidnet.service.adam.constant.AdamRedisConst.LOCK_KEY_UMEMBER_CODE;

@ApiSupport(order = 10031)
@Api(tags = "购买会员")
@Slf4j
@Validated
@RestController
@RequestMapping("member/order")
public class AdamMemberOrderController {
    @Autowired
    Environment env;
    @Autowired
    IAdamRdmService adamRdmService;
    @Autowired
    IAdamMemberOrderService adamMemberOrderService;
    @Autowired
    IAdamUserService adamUserService;

    @ApiOperationSupport(order = 0)
    @ApiOperation(value = "购买会员预览")
    @GetMapping("preview/{mno}/{id}")
    public ResponseDto<AdamMemberOrderPreviewVo> preview(@NotBlank @PathVariable String mno,
                                                         @NotBlank @PathVariable String id) {
        AdamMemberVo memberVo = adamRdmService.getMemberVoByMemberId(mno);
        if (null == memberVo) {
            return ResponseDto.failure(ErrorMapping.get("10201"));
        }

        AdamMemberOrderPreviewVo previewVo = AdamMemberOrderPreviewVo.getNew();
        previewVo.setMemberId(mno);
        previewVo.setMemberTitle(memberVo.getTitle());

        previewVo.setRealInfoVo(adamRdmService.getRealInfoVoByUid(CurrentUtil.getCurrentUid()));
        previewVo.setPriceVo(adamRdmService.getMemberPriceVoByPriceId(mno, id));

        AdamUserInfoVo userInfoVo = adamRdmService.getUserInfoVoByUid(CurrentUtil.getCurrentUid());
        previewVo.setBirthday(null == userInfoVo ? null : userInfoVo.getBirthday());

        return ResponseDto.success(previewVo);
    }

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "购买会员或会员码")
    @PostMapping("buy")
    public ResponseDto<AdamMemberOrderResult> buyMemberOrCode(@Valid @RequestBody AdamMemberOrderParam param) {
        log.debug("member/order/buy:param:{}", JsonUtils.toJson(param));
        String currentUid = CurrentUtil.getCurrentUid();

        if (checkMobileOrUid(currentUid)) {
            return ResponseDto.failure(ErrorMapping.get("10213"));
        }

        AdamRealInfoVo realInfoVo = adamRdmService.getRealInfoVoByUid(currentUid);
        if (null == realInfoVo) {
            if (StringUtils.isBlank(param.getName()) || StringUtils.isBlank(param.getIdCard())) {
                return ResponseDto.failure(ErrorMapping.get("10101"));
            }
            AdamRealInfoVo vo = adamUserService.identity(currentUid, param.getName(), param.getIdCard());
            if (null == vo) {
                return ResponseDto.failure(ErrorMapping.get("10000"));
            }
        }

        return adamMemberOrderService.buyMemberOrMemberCode(param);
    }

    /**
     * 当订单支付成功后，会立即通知Server一次，若未能响应成功，之后的24小时内会多次通知
     * 通知头：
     * {
     * "token":"eyJpdiI6IlJuTDFpOVBFOVBReUJ6OTd5ankzVVE9PSIsInZhbHVlIjoiMzhxWW52Um1lWVNYOEJ4OVh6OEdzUT09IiwibWFjIjoiM2Q4OWNkNWVkMjJkNzY0OGVjNmE5YTA3ODUwMTI5YWFlN2U5NDgwZmE0YmVmZWE4MTE1NmY1NWZjMGI2YmNiZCJ9"
     * }
     * 通知参数:
     * {
     * "status":"1",
     * "type":"MBEANS",
     * "code":"201807201217135B516249085EC",
     * "order_code":"00001TESTORDER",
     * "price":"0.01",
     * "payment_type":"APPIAP",
     * "payment_at":"2018-07-20 12:17:13",
     * "payment_id":"1032334083425793457349875"
     * }
     * 通知说明：已支付订单status为1，code为交易支付订单号，建议保存code，type为支付种类，payment_type为支付类型，以上参数是必传。
     * 通知响应：'success'，响应成功，将不再通知客户端
     * 通知响应：'fail'，响应失败，将不再通知客户端，建议在订单异常的状态下响应失败
     *
     * @return
     */
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "会员支付回调")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "status", value = "1-成功｜0-失败", example = "1"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "order_code", value = "会员订单号", example = "77062761607274496V"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "code", value = "支付订单号", example = "20210616153954199964032352974P"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "type", value = "购买类型", example = "VIP"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "price", value = "支付金额", example = "0.01"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payment_type", value = "支付类型", example = "WAPALIPAY"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payment_at", value = "支付时间", example = "2021-06-16 15:40:02"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payment_id", value = "支付ID", example = "2021061622001468121421203878"),
    })
    @PostMapping("callback")
    public String paymentNotifyCallBack() {
        log.debug("/member/callback.mapParameter:{}, token:{}", JsonUtils.toJson(ServletUtils.getRequest().getParameterMap()), ServletUtils.getRequest().getHeader("token"));
        // TODO: 2021/6/13 验签

        AdamMemberOrderCallbackParam parameter = AdamMemberOrderCallbackParam.getNew().get(ServletUtils.getRequest());
        if (1 != parameter.getStatus() ||
                !parameter.getType().equals("VIP") ||
                null == parameter.getOrderCode() ||
                null == parameter.getCode()) {
            log.error("会员支付回调参数有误:{}", JsonUtils.toJson(parameter));

            return "fail";
        }

        ResponseDto<Object> dto = adamMemberOrderService.paymentNotifyCallBack(parameter);

        if (!dto.isSuccess()) {
            log.warn("###会员支付回调处理失败:handleDto:{},CallbackParam:{}", JsonUtils.toJson(dto), JsonUtils.toJson(parameter));

            return "fail";
        }
        return "success";
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "兑换码校验", notes = "响应参数[`code`:0-当前兑换码可用，否则不可用]")
    @GetMapping("check/code")
    public ResponseDto<Integer> checkMemberCode(@NotBlank @RequestParam String mCode) {
        AdamMemberCodeVo vo = adamRdmService.getMemberCodeVoByCode(mCode);
        if (null == vo) {
            return ResponseDto.failure(ErrorMapping.get("10207"));
        }
        if (vo.getState() != 0) {
            return ResponseDto.failure(ErrorMapping.get(vo.getState() == 1 ? "10208" : "10209"));
        }
        return ResponseDto.success(0);
    }

    private boolean checkMobileOrUid(String uid) {
        List<String> blacklist = adamRdmService.getBlacklistForMember();
        return !CollectionUtils.isEmpty(blacklist) && blacklist.contains(uid);
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "使用兑换码")
    @PostMapping("exchange")
    public ResponseDto<AdamMemberOrderResult> exchangeMemberCode(@Valid @RequestBody AdamMemberOrderCodeParam param) {
        log.debug("member/order/exchange:param:{}", JsonUtils.toJson(param));
        String currentUid = CurrentUtil.getCurrentUid();
        // TODO: 2021/6/19 关闭该验证（如果已是会员继续兑换则保留原会员号，兑换码对应会员号记录至会员订单）
//        if (null != adamRdmService.getUserMemberVoByUid(currentUid)) {// 仅限从未购买过会员的用户使用
//            return ResponseDto.failure(ErrorMapping.get("10200"));
//        }

        if (checkMobileOrUid(currentUid)) {
            return ResponseDto.failure(ErrorMapping.get("10213"));
        }

        AdamRealInfoVo realInfoVo = adamRdmService.getRealInfoVoByUid(currentUid);
        if (null == realInfoVo) {
            if (StringUtils.isBlank(param.getName()) || StringUtils.isBlank(param.getIdCard())) {
                return ResponseDto.failure(ErrorMapping.get("10101"));
            }
            AdamRealInfoVo vo = adamUserService.identity(currentUid, param.getName(), param.getIdCard());
            if (null == vo) {
                return ResponseDto.failure(ErrorMapping.get("10000"));
            }
        }
        if (RedisLockUtil.tryLock(LOCK_KEY_UMEMBER_CODE + param.getMemberCode(), 1, 5)) {
            ResponseDto<AdamMemberOrderResult> responseDto = adamMemberOrderService.exchangeMemberCode(param);

            if (!responseDto.isSuccess()) {
                RedisLockUtil.unlock(LOCK_KEY_UMEMBER_CODE + param.getMemberCode());
            }
            return responseDto;
        } else {
            return ResponseDto.failure(ErrorMapping.get("10000"));
        }
    }

    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "会员订单列表")
    @GetMapping("list")
    public ResponseDto<PageInfo<AdamMemberOrderSimpleVo>> list(@RequestParam(defaultValue = "1", required = false) int pageNo,
                                                               @RequestParam(defaultValue = "5", required = false) int pageSize) {
        return ResponseDto.success(adamMemberOrderService.queryPage(CurrentUtil.getCurrentUid(), pageNo, pageSize));
    }

    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "会员订单详情")
    @GetMapping("info/{orderNo}")
    public ResponseDto<AdamMemberOrderVo> getMemberOrderList(@NotBlank @PathVariable String orderNo) {
        return ResponseDto.success(adamRdmService.getShotMemberOrderVoByOrderNo(orderNo));
    }

    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "会员订单状态")
    @GetMapping("check")
    public ResponseDto<Integer> checkOrderResult(@NotBlank @RequestParam String orderNo) {
        AdamMemberOrderVo memberOrderInfo = adamRdmService.getShotMemberOrderVoByOrderNo(orderNo);
        if (null == memberOrderInfo) {
            return ResponseDto.failure(ErrorMapping.get("10211"));
        }
        if (memberOrderInfo.getMode() <= 1) {
            try {
                // 支付中心返回说明:已支付订单status==1，未支付订单status==0
                String rst = HttpUtil.get(env.getProperty("liquidnet.url-pay.check") + "?code=" + memberOrderInfo.getPayNo(), null);

                JsonNode rstJNode = JsonUtils.fromJson(rst, JsonNode.class);

                int status = Integer.parseInt(rstJNode.get("status").asText("0"));

                return ResponseDto.success(status == 1 ? status : 0);
            } catch (Exception e) {
                log.error("支付中心:会员订单状态查询失败:{}", orderNo, e);
                return ResponseDto.failure(ErrorMapping.get("10212"));
            }
        }
        return ResponseDto.success(memberOrderInfo.getState());
    }
}
