package com.ff.weijinxiao.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ff.weijinxiao.config.WxPayProperties;
import com.ff.weijinxiao.domain.CUser;
import com.ff.weijinxiao.domain.MemberOrder;
import com.ff.weijinxiao.domain.MemberPackage;
import com.ff.weijinxiao.domain.UserInfo;
import com.ff.weijinxiao.jwt.JwtHelper;
import com.ff.weijinxiao.service.CUserService;
import com.ff.weijinxiao.service.MemberOrderService;
import com.ff.weijinxiao.service.UserInfoService;
import com.ff.weijinxiao.util.ResultTool;
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.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/wxpay")
@Api(value = "微信支付相关接口", tags = "微信支付相关接口")
public class WechatPayController {

    @Resource
    private WxPayService wxPayService;


    @Value("${wechat.pay.callback}")
    private String payCallBack;

    @Resource
    private WxPayProperties properties;

    @Resource
    private MemberOrderService memberOrderService;

    @Resource
    private CUserService cUserService;

    @Resource
    private UserInfoService userInfoService;

    public UserInfo getUserInfoByToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            return null;
        }
        String openId = JwtHelper.parseToken(token);
        if (StringUtils.isBlank(openId)) {
            return null;
        }

        CUser cUser = cUserService.findByOpenId(openId);
        if (null == cUser) {
            return null;
        }
        return cUser.getUserInfo();
    }

    @Transactional
    @ApiOperation(value = "微信支付接口", notes = "传入要支付的订单列表")
    @PostMapping("/pay")
    public Map<String, Object> pay(@ApiParam(value = "订单id", required = true) @RequestParam Integer orderId, HttpServletRequest httpServletRequest) {
        try {
            log.info("订单id =" + orderId);
            UserInfo userInfo = getUserInfoByToken(httpServletRequest);
            if (null == userInfo) {
                return ResultTool.genFailResult(ResultTool.ErrorCode_1, "获取失败，未注册有效账号");
            }
            JSONObject detailObj = new JSONObject();
            JSONArray jsonArray = new JSONArray();
            detailObj.put("goods_detail", jsonArray);
            String openId = userInfo.getWechatOpenid();
            String wechatSn = getWechatOrderNo();
            List<String> body = new ArrayList<>(16);
            Integer totalFee = Integer.valueOf(0);

            MemberOrder order = memberOrderService.findById(orderId);
            if (order == null) {
                return ResultTool.genFailResult(ResultTool.ErrorCode_1, "没有查询到订单！");
            }
            //保存更改
            order.setWechatSn(wechatSn);
            memberOrderService.saveMemberOrder(order);

            MemberPackage memberPackage = order.getMemberPackage();
            if (null != memberPackage) {
                body.add(memberPackage.getTitle());
            }
            //将元乘以100后取整
            if (null != order.getAmount()) {
                totalFee = order.getAmount().multiply(new BigDecimal("100")).setScale(0).intValue();
            }

            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            request.setBody(body + "_");
            request.setOutTradeNo(wechatSn);
            request.setTotalFee(totalFee);
            request.setSpbillCreateIp(getRemoteIP(httpServletRequest));
            request.setDetail(detailObj.toJSONString());
            request.setNotifyUrl(payCallBack + "/wxpay/notify/order");
            request.setTradeType(WxPayConstants.TradeType.JSAPI);
            request.setOpenid(openId);
            log.info("微信支付参数 = {}", request.toString());
            WxPayMpOrderResult payResult = wxPayService.createOrder(request);
            log.info("微信支付结果 = {}", payResult.toString());
            return ResultTool.genSuccessResult(payResult.toString());
        } catch (WxPayException e) {
            e.printStackTrace();
            return ResultTool.genFailResult(ResultTool.ErrorCode_1, e.getMessage());
        }
    }


    @ApiOperation(value = "支付回调通知处理")
    @PostMapping("/notify/order")
    public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
        WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
        log.info("parseOrderNotifyResult = {} ", notifyResult);
        if (notifyResult.getReturnCode().equals("SUCCESS") && notifyResult.getResultCode().equals("SUCCESS")) {
            String wechatSn = notifyResult.getOutTradeNo();
            MemberOrder order = memberOrderService.findByWechatSn(wechatSn);
            if (null == order) {
                log.info("微信支付单号{}对应的订单不存在或已支付！", wechatSn);
                return WxPayNotifyResponse.success("SUCCESS");
            }
            //校验一下金额是否符合
            Integer totalFee = notifyResult.getTotalFee();
            Integer totalAmount = Integer.valueOf(order.getAmount().multiply(new BigDecimal("100")).setScale(0).toString());
            log.info("支付订单总金额{},支付总金额{}", totalAmount, totalFee);
            if (!totalAmount.equals(totalFee)) {
                log.info("订单异常，支付总金额与订单总金额不相同！");
                return WxPayNotifyResponse.success("SUCCESS");
            }
            //更新状态为已支付
            order.setStatus(1);

            //跟新微信支付流水号 供退款使用
            order.setTransactionId(notifyResult.getTransactionId());
            order.setPaymentTime(DateUtil.date());
            memberOrderService.saveMemberOrder(order);

            //支付成功更新可最多设置记账人数
            String uid = order.getUid();
            UserInfo userInfo = userInfoService.findByUid(uid);
            if (null != userInfo) {
                Integer accountBookNum = userInfo.getAccountBookNum();
                if(null == accountBookNum) {
                    accountBookNum = 1;
                }
                log.info("更新之前最多记账人数={}", accountBookNum);
                userInfo.setAccountBookNum(accountBookNum + order.getPackageNum());//设置记账最多人数
                log.info("更新之后最多记账人数={}", accountBookNum);
                Date validityTime = userInfo.getValidityTime();
                if(null == validityTime) {
                    validityTime = DateUtil.date();
                }
                validityTime = addDate(validityTime, 365*order.getPackageYears());
                userInfo.setIsvip(2);
                userInfo.setValidityTime(validityTime);
                userInfoService.saveUserInfo(userInfo);
            }

            log.info("微信支付回调返回Success");
            return WxPayNotifyResponse.success("SUCCESS");
        }
        log.error("支付回调通知处理失败");
        return WxPayNotifyResponse.fail("FAIL");
    }

    public static void main(String[] args) throws ParseException {
/*        Date validityTime = DateUtil.date();
        validityTime = addDate(validityTime, 365);
        System.out.println(validityTime);// 输出格式化后的日期*/
    }

    public Date addDate(Date date,long day) {
        long time = date.getTime(); // 得到指定日期的毫秒数
        day = day*24*60*60*1000; // 要加上的天数转换成毫秒数
        time+=day; // 相加得到新的毫秒数
        return DateUtil.date(time); // 将毫秒数转换成日期
    }
/*
    @GetMapping("/order/refund")
    @ApiOperation(value = "微信支付，向微信退款申请", notes = "传入需要退款的订单号")
    public CommonResult refund(@ApiParam(value = "订单id", required = true) @RequestParam Long orderId,
                               @ApiParam(value = "退款金额", required = true) @RequestParam String returnAmount,
                               @ApiParam(value = "退款原因", required = false) @RequestParam String reason,
                               @ApiParam(value = "退货人姓名", required = false) @RequestParam String returnName,
                               @ApiParam(value = "退货人电话", required = false) @RequestParam String returnPhone) throws WxPayException {
        log.info("refund orderId= {} ", orderId);
        OmsOrder order = orderService.selectByPrimaryKey(orderId);
        if (null == order) {
            return CommonResult.failed("原订单不存在");
        }
        if (order.getStatus() == 5) {
            return CommonResult.failed("订单已在退款中，请勿重复操作");
        }


        WxPayRefundRequest request = new WxPayRefundRequest();
        //跟out_trade_no二选一
        request.setTransactionId(order.getTransactionId());
        request.setOutRefundNo(order.getWechatSn());
        Integer totalFee = order.getTotalAmount().multiply(new BigDecimal("100")).intValue();
        request.setTotalFee(totalFee);
        Integer refundFee = new BigDecimal(returnAmount).multiply(new BigDecimal("100")).intValue();
        if (null == refundFee || null == totalFee) {
            return CommonResult.failed("退款金额错误");
        }
        if (null != refundFee && null != totalFee && refundFee > totalFee) {
            return CommonResult.failed("退款金额不可以大于订单金额");
        }
        request.setRefundFee(refundFee);
        //默认为商户号
        request.setOpUserId(properties.getMchId());
        log.info("退款信息:" + request.toString());
        WxPayRefundResult refundResult = wxPayService.refund(request);
        log.info("退款结果:" + refundResult.toString());
        if (refundResult.getReturnCode().equals("SUCCESS")) {
            OmsOrderReturnApplyExample example = new OmsOrderReturnApplyExample();
            OmsOrderReturnApplyExample.Criteria criteria = example.createCriteria();
            criteria.andOrderSnEqualTo(order.getOrderSn());
            List<OmsOrderReturnApply> list = omsOrderReturnApplyMapper.selectByExample(example);
            if (null != list && list.size() > 0) {
                for (OmsOrderReturnApply orderReturnApply : list) {
                    orderReturnApply.setStatus(2);
                    omsOrderReturnApplyMapper.updateByPrimaryKey(orderReturnApply);
                }
            }
            order.setStatus(6);//设置为退款完成
            orderService.updateByPrimaryKey(order);

            return CommonResult.success("退款申请成功！");
        }

        return CommonResult.failed("退款申请失败！");
    }
*/


    public String getWechatOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
        String format = sdf.format(new Date()) + getRandomString();
        return "2000" + format;
    }

    private String getRandomString() {
        Random random = new Random();
        String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 7; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public String getRemoteIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }


}
