package com.fzm.mall.server.front.order.controller.weixinPay;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fzm.mall.server.front.base.ResponseVO;
import com.fzm.mall.server.front.constant.MallResponseEnum;
import com.fzm.mall.server.front.enums.QueueTypeEnum;
import com.fzm.mall.server.front.goods.model.PreSale;
import com.fzm.mall.server.front.goods.model.vo.SkuVo;
import com.fzm.mall.server.front.mq.MsgProducer;
import com.fzm.mall.server.front.order.mapper.OrderMapper;
import com.fzm.mall.server.front.order.model.*;
import com.fzm.mall.server.front.order.model.vo.OrderSkuVo;
import com.fzm.mall.server.front.order.model.vo.PayVo;
import com.fzm.mall.server.front.order.model.vo.WCPayResultVo;
import com.fzm.mall.server.front.order.service.IPayService;
import com.fzm.mall.server.front.redis.OrderRedis;
import com.fzm.mall.server.front.user.model.Header;
import com.fzm.mall.server.front.util.HttpUtil;
import com.fzm.mall.server.front.util.UUIdUtil;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;

import io.netty.util.internal.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jdk.nashorn.internal.ir.annotations.Ignore;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import org.jdom2.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Api(tags = "微信支付", description = "微信支付")
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping(value = "/mall/wxpay", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class WeiXinPayController {

    @Autowired
    private WxPayJsApi wxPayJsApi;

    @Autowired
    private IPayService payService;

    @Autowired
    private CreateSign createSign;

    @Autowired
    private  WeiXinPay weiXinPay;

    @Autowired
    private MsgProducer msgProducer;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderRedis orderRedis;




    @ApiOperation(value = "支付 参数 pid")
    @PostMapping("/without/pay")
    public ResponseVO<WCPayResultVo> pay(@Ignore @RequestAttribute Header header, @RequestBody PayVo payVo) {
        Pay pay = payService.getByPidAndUid(payVo.getPid(), header.getUid());

        if(pay == null){
            return  new ResponseVO<WCPayResultVo>(MallResponseEnum.PARAMETER_ERR);
        }
        if(pay.getState()!=3&&pay.getState()!=6){
            return new ResponseVO<WCPayResultVo>(MallResponseEnum.ORDER_NOT_PAY);
        }
        String name = payService.getGoodsName(pay);
        pay.setPayType(2);
        pay.setState(3);
        if (payVo.getPayType() == 0) {

        } else if (payVo.getPayType() == 2) {
            try {
                if(payVo.getModel() == 1){
                    if (StringUtil.isNullOrEmpty(payVo.getOpenId())) {
                        return new ResponseVO<WCPayResultVo>(MallResponseEnum.PARAMETER_ERR);
                    }
                    JSONObject reqdata = new JSONObject();
                    reqdata.put("appid", WeiXinProties.getAPP_ID());
                    reqdata.put("mchid", WeiXinProties.getMERC_ID());
                    reqdata.put("description", name);
                    reqdata.put("out_trade_no",  payVo.getPid());
                    reqdata.put("notify_url", WeiXinProties.getNOTIFY_URL());
                    JSONObject data = new JSONObject();
                    data.put("total",pay.getUnpaidAmount().multiply(BigDecimal.valueOf(100)).intValue());
                    reqdata.put("amount",data);
                    //reqdata.put("openid",openId);
                    data = new JSONObject();
                    data.put("openid",payVo.getOpenId());
                    reqdata.put("payer",data);
                    String prepayId = wxPayJsApi.CreateOrder(reqdata);
                    String str = "prepay_id="+prepayId;
                    HttpUrl httpUrl = HttpUrl.get("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
                    //时间戳
                    long timestamp = System.currentTimeMillis() / 1000;
                    String uuid = UUIdUtil.getUUID();
                    WCPayResultVo payResultVo = new WCPayResultVo();
                    payResultVo.setPrePayId(str);
                    payResultVo.setNoncestr(uuid);
                    String sign = createSign.sign(uuid, timestamp + "", str);
                    payResultVo.setSign(sign);
                    payResultVo.setTimeStamp(timestamp+"");
                    payResultVo = createSign.getToken(payResultVo);
                    pay.setPayInfo(JSON.toJSONString(payResultVo));
                    payService.updateById(pay);
                    return new ResponseVO<WCPayResultVo>(MallResponseEnum.SUCCESS, payResultVo);
                }else{
                    JSONObject reqdata = new JSONObject();
                    reqdata.put("appid", WeiXinProties.getWX_APP_ID());
                    reqdata.put("mchid", WeiXinProties.getMERC_ID());
                    reqdata.put("description", name);
                    reqdata.put("out_trade_no",  payVo.getPid());
                    reqdata.put("notify_url", WeiXinProties.getNOTIFY_URL());
                    JSONObject data = new JSONObject();
                    data.put("total",pay.getUnpaidAmount().multiply(BigDecimal.valueOf(100)).intValue());
                    reqdata.put("amount",data);
                    //reqdata.put("openid",openId);
                    //data = new JSONObject();
                    //data.put("openid",payVo.getOpenId());
                    //reqdata.put("payer",data);
                    String prepayId = wxPayJsApi.CreateAppOrder(reqdata);
                    //String str = "prepay_id="+prepayId;
                    HttpUrl httpUrl = HttpUrl.get("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
                    //时间戳
                    long timestamp = System.currentTimeMillis() / 1000;
                    String uuid = UUIdUtil.getUUID();
                    WCPayResultVo payResultVo = new WCPayResultVo();
                    payResultVo.setPrePayId(prepayId);
                    payResultVo.setNoncestr(uuid);
                    String sign = weiXinPay.wxAppSign(WeiXinProties.getWX_APP_ID(),timestamp+"",uuid,prepayId);
                    payResultVo.setSign(sign);
                    payResultVo.setTimeStamp(timestamp+"");
                   // payResultVo = createSign.getWxToken(payResultVo);
                    pay.setPayInfo(JSON.toJSONString(payResultVo));
                    payService.updateById(pay);
                    return new ResponseVO<WCPayResultVo>(MallResponseEnum.SUCCESS, payResultVo);
                }
            } catch (Exception e) {
                log.error(e.toString());
            }
        }
        return null;
    }

    public String getOpenId(String code) {
        try {
            if (StringUtil.isNullOrEmpty(code)) {
                return "";
            }
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+WeiXinProties.getAPP_ID()+"&secret="+WeiXinProties.getSECRET()+"&code=" + code + "&grant_type=authorization_code";
            String s = HttpUtil.httpGet(url);
            JSONObject object = JSON.parseObject(s);
            String openId = object.getString("openid");
            return openId;
        } catch (Exception e) {
            return "";
        }

    }

    @ApiOperation(value = "获取OpenId")
    @PostMapping("/without/getOpenId")
    public ResponseVO<String> getOpenId(@RequestBody JSONObject data) {
        String code = data.getString("code");
        if (StringUtil.isNullOrEmpty(code)) {
            return new ResponseVO<String>(MallResponseEnum.PARAMETER_ERR);
        }
        String openId = getOpenId(code);
        if (StringUtil.isNullOrEmpty(openId)) {
            return new ResponseVO<String>(MallResponseEnum.PARAMETER_ERR);
        }
        return new ResponseVO<String>(MallResponseEnum.SUCCESS, openId);
    }

    //@ApiOperation(value = "获取OpenId")
    @PostMapping("/without/return")
    public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.error("微信支付回调");
        String notifySign = "%s\n%s\n%s\n";
        Enumeration<String> headerNames = request.getHeaderNames();
        String body = getBodytxt(request);//获取body数据,需要自实现
        log.error(body);
        JSONObject head = new JSONObject();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            String value = request.getHeader(key);
            head.put(key, value);
        }
        log.info("微信通知头部" + head);
        log.info("微信通知body" + body);
        weiXinPay.verify(head.getString("wechatpay-serial"), String.format(notifySign, head.getString("wechatpay-timestamp"), head.getString("wechatpay-nonce"), body), head.getString("wechatpay-signature"));
        JSONObject notify = weiXinPay.notify(JSONObject.parseObject(body));
        if(notify != null){
            String pid = notify.getString("out_trade_no");
            if(StringUtil.isNullOrEmpty(pid)){
                log.error("notifyWeiXinPay:"+"out_trade_no is null");
                JSONObject result = new JSONObject();
                result.put("code","SUCCESS");
                result.put("message","成功");
                return result.toString();
            }
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
            Pay byPid = payService.getByPid(pid);
            byPid.setPaidAmount(byPid.getUnpaidAmount());
            byPid.setUnpaidAmount(BigDecimal.ZERO);
            byPid.setPayTime(format.parse(notify.getString("success_time")).getTime());
            byPid.setState(1);
            byPid.setOutBizNo(notify.getString("transaction_id"));
            payService.updateById(byPid);
            JSONArray array = JSONArray.parseArray(byPid.getOidsJson());
            for (Object oid : array) {
                Order order = orderMapper.getByOid(oid.toString());
                orderMapper.paySuccess(oid.toString(), System.currentTimeMillis());
                orderRedis.delOrder(oid.toString());
                    /*//支付记录
                    PayRecord payRecord = new PayRecord();
                    payRecord.setPayId(pid);
                    payRecord.setOid(oid.toString());
                    payRecord.setPayTime(System.currentTimeMillis());
                    payRecord.setPayType(pay.getPayType());
                    payRecord.setMerchantId(order.getMerchantId());
                    payRecord.setPayAmount(order.getAmount());
                    payRecord.setState(1);
                    payRecordService.save(payRecord);*/
            }
            msgProducer.send(pid, QueueTypeEnum.ORDER_PAY);
            log.error("notify:"+notify.toString());
        }
        JSONObject result = new JSONObject();
        result.put("code","SUCCESS");
        result.put("message","成功");
        return result.toString();
    }
    String getBodytxt(HttpServletRequest request) throws IOException {
        BufferedReader br = request.getReader();
        String str, wholeStr = "";
        while((str = br.readLine()) != null){
            wholeStr += str;
        }
        return wholeStr;
    }

}
