package com.sien.common.service.impl;

import cn.hutool.captcha.generator.RandomGenerator;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.sien.common.entity.AppUser;
import com.sien.common.entity.VipRecord;
import com.sien.common.mapper.VipRecordMapper;
import com.sien.common.param.VipOpenParam;
import com.sien.common.param.VipRecordPageParam;
import com.sien.common.service.AppUserService;
import com.sien.common.service.VipPriceService;
import com.sien.common.service.VipRecordService;
import com.sien.common.vo.AppUserQueryVo;
import com.sien.common.vo.VipRecordQueryVo;
import com.sien.common.vo.app.VipPriceQueryVo;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;

/**
 * Vip开通记录 服务实现类
 *
 * @author hewei
 * @since 2021-02-25
 */
@Slf4j
@Service
public class VipRecordServiceImpl extends BaseServiceImpl<VipRecordMapper, VipRecord> implements VipRecordService {


    private static final String BODY = "厦门市四恩慈善会开通会员";

    private static final String NOTIFY_URL = "/api/pay/notify/vipOrder";

    @Autowired
    private VipRecordMapper vipRecordMapper;

    @Autowired
    private WxPayService wxService;

    @Autowired
    private AppUserService appUserService;
    @Resource
    HttpServletRequest httpServletRequest;

    @Autowired
    private VipPriceService vipPriceService;

    @Value("${spring-boot-plus.domain}")
    private String domain;

    @Override
    public String vipOrderNotifyResult(String xmlData) {

        WxPayOrderNotifyResult notifyResult;
        try {
            notifyResult = this.wxService.parseOrderNotifyResult(xmlData);
        } catch (WxPayException e) {
            // 是否能解密成功
            e.printStackTrace();
            return WxPayNotifyResponse.fail("错误");
        }

        VipRecord vipRecord = super.getOne(new QueryWrapper<VipRecord>().lambda().eq(VipRecord::getWxMerPayId, notifyResult.getOutTradeNo()));

        // 如果已经支付 直接响应成功
        if (vipRecord.getPayStatus() == 1) {
            return WxPayNotifyResponse.successResp("成功");

        }

        vipRecord.setPayStatus(1);
        vipRecord.setPayTime(new Date());

        super.updateById(vipRecord);

        return WxPayNotifyResponse.successResp("成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveVipRecord(VipRecord vipRecord) throws Exception {
        return super.save(vipRecord);
    }


    private WxPayMpOrderResult getWxPayMpOrderResult(String outTradeNo, String openid, String spbillCreateIp, int totalFee) throws WxPayException {

        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();

        wxPayUnifiedOrderRequest.setBody(VipRecordServiceImpl.BODY);

        // 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
        wxPayUnifiedOrderRequest.setOutTradeNo(outTradeNo);

        //订单总金额，单位为分，详见支付金额
        wxPayUnifiedOrderRequest.setTotalFee(totalFee);

        // APP和网页支付提交用户端ip
        wxPayUnifiedOrderRequest.setSpbillCreateIp(spbillCreateIp);

        // 接收微信支付异步通知回调地址，通知url必须为直接可访问的url，不能携带参数。
        wxPayUnifiedOrderRequest.setNotifyUrl(domain + VipRecordServiceImpl.NOTIFY_URL);

        wxPayUnifiedOrderRequest.setOpenid(openid);
        String jsapi = "JSAPI";
        wxPayUnifiedOrderRequest.setTradeType(jsapi);

        WxPayMpOrderResult order = null;
//        try {
        order = this.wxService.createOrder(wxPayUnifiedOrderRequest);
//        } catch (WxPayException e) {
//            e.printStackTrace();
//        }
        return order;
    }


    @Override
    public ApiResult<WxPayMpOrderResult> openVip(VipOpenParam vipOpenParam) throws Exception {
        JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();

        AppUserQueryVo appUserById = appUserService.getAppUserById(jwtToken.getUserId());

        // 获取vip价格表
        VipPriceQueryVo vipPriceById = vipPriceService.getVipPriceById(vipOpenParam.getVipLevelId());
        if (vipPriceById == null) {
            return ApiResult.fail(ApiCode.FAIL, null);
        }

        // 应付金额
        BigDecimal money = vipPriceById.getPrice().multiply(new BigDecimal(vipOpenParam.getYears()));
        // 设置到期时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, vipOpenParam.getYears());
        Date expiredAt = calendar.getTime();

        // 商家订单号
        String outTradeNo = new RandomGenerator(32).generate();

        VipRecord vipRecord = new VipRecord();
        vipRecord.setMoney(money);
        vipRecord.setExpiredAt(expiredAt);
        vipRecord.setYears(vipOpenParam.getYears());
        vipRecord.setPayStatus(0);

        vipRecord.setWxMerPayId(outTradeNo);

//        // 判断是否为替他人
        if (vipOpenParam.getIsReplace() == 1) {

            // 判断接收人不能为自己
            if (appUserById.getPhoneArea().equals(vipOpenParam.getPhoneArea()) &&
                    appUserById.getPhone().equals(vipOpenParam.getUserPhone())) {
                return ApiResult.fail(ApiCode.PHONE_IS_ME, new WxPayMpOrderResult());
            }

            AppUser user = appUserService.getOne(new QueryWrapper<AppUser>().lambda()
                    .eq(AppUser::getPhone, vipOpenParam.getUserPhone())
                    .eq(AppUser::getPhoneArea, vipOpenParam.getPhoneArea()));
            //判断接收方是否存在
            if (user == null) {
                return ApiResult.fail(ApiCode.USER_NOT_FOUND, new WxPayMpOrderResult());
            }
            vipRecord.setFkUserId(user.getId());
            vipRecord.setFkRechargeUser(jwtToken.getUserId());

        } else {
            vipRecord.setFkUserId(jwtToken.getUserId());
            vipRecord.setFkRechargeUser(-1L);
        }

        // 保存数据库
        boolean save = super.save(vipRecord);
        if (save) {
            // 保存成功调用微信支付
            String ip = httpServletRequest.getRemoteAddr();
            BigDecimal num2 = new BigDecimal(100);
            int totalFee = money.multiply(num2).intValue();
            WxPayMpOrderResult wxPayMpOrderResult = getWxPayMpOrderResult(outTradeNo, appUserById.getWechatOpenId(), ip, totalFee);
            return ApiResult.ok(wxPayMpOrderResult);

        } else {
            return ApiResult.fail(ApiCode.FAIL, null);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateVipRecord(VipRecord vipRecord) throws Exception {
        return super.updateById(vipRecord);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteVipRecord(Long id) throws Exception {
        return super.removeById(id);
    }

    @Override
    public VipRecordQueryVo getVipRecordById(Long id) throws Exception {
        return vipRecordMapper.getVipRecordById(id);
    }

    @Override
    public Paging<VipRecordQueryVo> getVipRecordPageList(VipRecordPageParam vipRecordPageParam) throws Exception {
        Page<VipRecordQueryVo> page = new PageInfo<>(vipRecordPageParam, OrderItem.desc(getLambdaColumn(VipRecord::getCreateTime)));
        IPage<VipRecordQueryVo> iPage = vipRecordMapper.getVipRecordPageList(page, vipRecordPageParam);
        return new Paging<VipRecordQueryVo>(iPage);
    }

}
