package com.miaxis.app.controller.wx;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.miaxis.common.config.WxpayConfig;
import com.miaxis.common.constant.Constants;
import com.miaxis.common.core.domain.entity.UserInfo;
import com.miaxis.common.exception.CustomException;
import com.miaxis.common.utils.AesUtil;
import com.miaxis.extension.service.IWxExtensionIncomeService;
import com.miaxis.feign.dto.WxGzhMini;
import com.miaxis.feign.dto.WxMessageTemplate;
import com.miaxis.feign.service.IWxSendService;
import com.miaxis.framework.web.service.TokenService;
import com.miaxis.user.service.IUserInfoService;
import com.miaxis.wx.domain.RefundRecord;
import com.miaxis.wx.domain.WxOrder;
import com.miaxis.wx.dto.WxNotifyReturnDTO;
import com.miaxis.wx.dto.WxpayNotifyDTO;
import com.miaxis.wx.service.IRefundRecordService;
import com.miaxis.wx.service.IWxGzhService;
import com.miaxis.wx.service.IWxOrderService;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;

@RestController
@RequiredArgsConstructor
@RequestMapping(Constants.OPEN_PREFIX+"/wx/notify")
@Api(tags = {"【H5-微信回调】"})
@Slf4j
public class WxNotifyController {


    @Autowired
    private WxpayConfig wxpayConfig;


    @Autowired
    private IWxOrderService wxOrderService;


    @Autowired
    private IUserInfoService userInfoService;

    @Autowired
    private  IRefundRecordService  refundRecordService;

    @Autowired
    private AutoUpdateCertificatesVerifier verifier;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private IWxExtensionIncomeService wxExtensionIncomeService;

    @Autowired
    private IWxSendService wxSendService;

    @Autowired
    private IWxGzhService wxGzhService;



    /**
     * 微信支付回调接口
     */
    @PostMapping(value = "/wxpay")
    @ApiOperation("微信支付回调")
    public WxNotifyReturnDTO wxpayNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
        String bodyString = getBodyString(request);
//        if (!validate(request,bodyString)){
//            throw new CustomException("签名失败");
//        }
        String resourceString = getSourString(wxpayNotifyDTO);
        log.info("微信支付回调数据"+resourceString);
        JSONObject jsonObject = JSONObject.parseObject(resourceString);
        //将回调数据写入数据库, 并成为会员
        writeNotifyDataToDb(jsonObject);
        WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
        wxNotifyReturnDTO.setCode("SUCCESS");
        wxNotifyReturnDTO.setMessage("成功");
        return wxNotifyReturnDTO;
    }



    private String getBodyString(HttpServletRequest request) {
            BufferedReader br = null;
            StringBuilder sb = new StringBuilder("");
            try
            {
                br = request.getReader();
                String str;
                while ((str = br.readLine()) != null)
                {
                    sb.append(str);
                }
                br.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            finally
            {
                if (null != br)
                {
                    try
                    {
                        br.close();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();

    }

    private Boolean validate(HttpServletRequest request, String bodyString) throws  NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        String sign = request.getHeader("Wechatpay-Signature");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");

        StringBuffer sb = new StringBuffer();
        sb.append(timestamp + "\n");
        sb.append(nonce + "\n");
        sb.append(bodyString + "\n");
        X509Certificate validCertificate = verifier.getValidCertificate();
        // 进行签名服务
        Signature signature = Signature.getInstance("SHA256withRSA");
        // 用微信平台公钥对签名器进行初始化
        signature.initVerify(validCertificate);
        // 把我们构造的验签名串更新到签名器中
        signature.update(sb.toString().getBytes(StandardCharsets.UTF_8));
        Boolean result = signature.verify(Base64Utils.decodeFromString(sign));
        log.info("微信支付回调验签:"+result.toString());
        return result;

    }


    /**
     * 微信退款回调
     */
    @PostMapping(value = "/refund")
    @ApiOperation("微信退款回调")
    public WxNotifyReturnDTO refundNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
        String bodyString = getBodyString(request);
        if (!validate(request,bodyString)){
            throw new CustomException("签名失败");
        }
        String resourceString = getSourString(wxpayNotifyDTO);
        log.info(resourceString);
        JSONObject jsonObject = JSONObject.parseObject(resourceString);
        //将回调数据写入数据库
        writeRefundNotifyDataToDb(jsonObject);

        WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
        wxNotifyReturnDTO.setCode("SUCCESS");
        wxNotifyReturnDTO.setMessage("成功");

        return wxNotifyReturnDTO;
    }

    private void writeRefundNotifyDataToDb(JSONObject jsonObject) {
        String refundId = jsonObject.getString("refund_id");
        RefundRecord refundRecord = refundRecordService.getByRefundId(refundId);
        if (refundRecord == null) {
            throw new CustomException("该退款订单不存在");
        }
        refundRecord.setTransactionId(jsonObject.getString("transaction_id"));
        refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
        refundRecord.setStatus(jsonObject.getString("refund_status"));
        refundRecordService.updateById(refundRecord);


    }






    public String writeNotifyDataToDb(JSONObject jsonObject) {
        String outTradeNo = jsonObject.getString("out_trade_no");
        WxOrder wxOrder = wxOrderService.getByOutTradeNo(outTradeNo);
        if (wxOrder == null) {
            throw new CustomException("该订单不存在");
        }
        wxOrder.setTransactionId(jsonObject.getString("transaction_id"));
        JSONObject amount = jsonObject.getJSONObject("amount");
        wxOrder.setPayerTotal(amount.getInteger("payer_total"));
        wxOrder.setTotal(amount.getInteger("total"));
        wxOrder.setCurrency(amount.getString("currency"));
        wxOrder.setPayerCurrency(amount.getString("payer_currency"));
        wxOrder.setTradeState(jsonObject.getString("trade_state"));
        wxOrder.setBankType(jsonObject.getString("bank_type"));
        DateTime dateTime  = new DateTime(jsonObject.getString("success_time"));
        wxOrder.setSuccessTime(dateTime.toDate());
        wxOrder.setTradeStateDesc(jsonObject.getString("trade_state_desc"));
        wxOrder.setTradeType(jsonObject.getString("trade_type"));
        wxOrder.setAttach(jsonObject.getString("attach"));
        JSONObject sceneInfo = jsonObject.getJSONObject("scene_info");
        if (sceneInfo != null){
            wxOrder.setDeviceId(sceneInfo.getString("device_id"));
        }
        wxOrderService.updateById(wxOrder);

        //成为会员
        String data = wxOrder.getOrderDataJson();
        int days;
        try{
            days = Integer.valueOf(data);
        }catch (Exception e){
            throw new CustomException("参数值转化异常，请检查数据是否为数值类型");
        }
        long timeMillis = days*1440*60*1000l;
        UserInfo userinfo = userInfoService.getOne(new QueryWrapper<UserInfo>().eq("openid", wxOrder.getOpenid()));
        Date expireTime = userinfo.getExpireTime();
        if (expireTime == null || expireTime.getTime()< System.currentTimeMillis()){
            userinfo.setExpireTime(new Date(System.currentTimeMillis()+timeMillis));
        }else{
            userinfo.setExpireTime(new Date(expireTime.getTime()+timeMillis));
        }

        userInfoService.updateById(userinfo);

        //更新上下文中对象状态
//        LoginUser loginUser = SecurityUtils.getLoginUser();
////        loginUser.setStudent(userinfo);
////        //刷新缓存中的数据
////        tokenService.refreshToken(loginUser);

        //发送模板消息
        messageTemplateSend(userinfo,wxOrder);

        // 分成
        wxExtensionIncomeService.addExtensionIncomeBySourceId(wxOrder.getOutTradeNo(),wxOrder.getOpenid(),wxOrder.getTotal());

        return outTradeNo;

    }

    private String getSourString(WxpayNotifyDTO wxpayNotifyDTO) throws GeneralSecurityException, IOException {
        AesUtil aesUtil = new AesUtil(wxpayConfig.getV3key().getBytes());
        WxpayNotifyDTO.WxpaySource wxpaySource = wxpayNotifyDTO.getResource();
        return aesUtil.decryptToString(wxpaySource.getAssociated_data().getBytes(), wxpaySource.getNonce().getBytes(), wxpaySource.getCiphertext());
    }


    /**
     * 发送模板信息
     * @param userInfo 用户信息
     * @param wxOrder 订单信息
     */
    private void messageTemplateSend(UserInfo userInfo,WxOrder wxOrder){

        //获取tolen
        String token = wxGzhService.getGzhToken();

        WxMessageTemplate messageTemplate = new WxMessageTemplate();
        messageTemplate.setTouser(userInfo.getOpenid());
        messageTemplate.setTemplate_id("d1P87FFAAos_sHteTCA-slkFJesE8xkoDsRImVa58jc");
        messageTemplate.setUrl("https://jpcj-h5.zzxcx.net");
        WxGzhMini wxGzhMini = new WxGzhMini();
        messageTemplate.setMiniprogram(wxGzhMini);

        JSONObject jsonObject = new JSONObject();
        JSONObject first = new JSONObject();
        JSONObject keyword1 = new JSONObject();
        JSONObject keyword2 = new JSONObject();
        JSONObject keyword3 = new JSONObject();
        JSONObject keyword4 = new JSONObject();
        JSONObject keyword5 = new JSONObject();
        JSONObject remark = new JSONObject();
        first.put("value","恭喜您开通金牌车教会员成功！");
        first.put("color","#173177");
        keyword1.put("value","VIP会员");
        keyword1.put("color","#173177");
        keyword2.put("value", userInfo.getNickName());
        keyword2.put("color","#173177");
        keyword3.put("value","支付成功");
        keyword3.put("color","#173177");
        keyword4.put("value",wxOrder.getTotal()/100);
        keyword4.put("color","#173177");
        keyword5.put("value",DateUtil.format(userInfo.getExpireTime(), "yyyy-MM-dd HH:mm"));
        keyword5.put("color","#173177");
        remark.put("value","即日起，即可想享受会员特权");
        remark.put("color","#173177");
        jsonObject.put("first",first);
        jsonObject.put("keyword1",keyword1);
        jsonObject.put("keyword2",keyword2);
        jsonObject.put("keyword3",keyword3);
        jsonObject.put("keyword4",keyword4);
        jsonObject.put("keyword5",keyword5);
        jsonObject.put("remark",remark);
        messageTemplate.setData(jsonObject);
        String result = wxSendService.messageTemplateSend(token,messageTemplate);
        JSONObject parseObject = JSONObject.parseObject(result);
        log.info("模板消息：[{}],响应信息：[{}]",messageTemplate,parseObject);

    }





}
