package com.zhongzheng.modules.wx.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.zhongzheng.common.config.WxSmallConfig;
import com.zhongzheng.common.core.redis.RedisCache;
import com.zhongzheng.common.exception.CustomException;
import com.zhongzheng.common.utils.AES;
import com.zhongzheng.common.utils.DateUtils;
import com.zhongzheng.common.utils.ServletUtils;
import com.zhongzheng.common.utils.SnowflakeIdUtils;
import com.zhongzheng.common.utils.http.HttpUtils;
import com.zhongzheng.common.utils.ip.IpUtils;
import com.zhongzheng.common.utils.polyv.PolyvUtils;
import com.zhongzheng.common.utils.wxpay.*;
import com.zhongzheng.modules.bank.domain.QuestionBank;
import com.zhongzheng.modules.course.domain.Course;
import com.zhongzheng.modules.course.service.ICourseService;
import com.zhongzheng.modules.exam.service.IExamNoteService;
import com.zhongzheng.modules.order.bo.OrderGoodsAddBo;
import com.zhongzheng.modules.order.bo.OrderGoodsQueryBo;
import com.zhongzheng.modules.order.domain.Order;
import com.zhongzheng.modules.order.domain.OrderCoupon;
import com.zhongzheng.modules.order.service.IOrderCouponService;
import com.zhongzheng.modules.order.service.IOrderGoodsService;
import com.zhongzheng.modules.order.service.IOrderService;
import com.zhongzheng.modules.order.vo.OrderGoodsVo;
import com.zhongzheng.modules.polyv.bo.PolyvVideoAddBo;
import com.zhongzheng.modules.polyv.bo.PolyvVideoEditBo;
import com.zhongzheng.modules.polyv.bo.PolyvVideoQueryBo;
import com.zhongzheng.modules.polyv.domain.PolyvVideDo;
import com.zhongzheng.modules.polyv.domain.PolyvVideo;
import com.zhongzheng.modules.polyv.domain.TokenResponse;
import com.zhongzheng.modules.polyv.mapper.PolyvVideoMapper;
import com.zhongzheng.modules.polyv.service.IPolyvVideoService;
import com.zhongzheng.modules.polyv.vo.PolyvVideoQuerVo;
import com.zhongzheng.modules.polyv.vo.PolyvVideoVo;
import com.zhongzheng.modules.user.bo.OrderPossessUserAddBo;
import com.zhongzheng.modules.user.domain.User;
import com.zhongzheng.modules.user.service.IOrderPossessUserService;
import com.zhongzheng.modules.user.service.IUserService;
import com.zhongzheng.modules.wx.service.IWxPayService;
import com.zhongzheng.modules.wx.vo.WxPayVo;
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 java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.squareup.okhttp.internal.Util.md5Hex;

/**
 * 保利威视频信息Service业务层处理
 *
 * @author ruoyi
 * @date 2021-06-11
 */
@Service
public class WxPayServiceImpl  implements IWxPayService {

    @Value("${wx.small.appid}")
    private String appid;

    @Value("${wx.gzh.appid}")
    private String gzhAppid;

    @Value("${wx.gzh.appsecret}")
    private String gzh_appsrcret;

    @Value("${wx.wepay.mchid}")
    private String mchid;

    @Value("${wx.wepay.key}")
    private String key;

    @Value("${wx.wepay.appsecret}")
    private String appsecret;

    @Autowired
    private RedisCache redisCache;

    private WXPayConstants.SignType signType;

    private String notifyUrl = "https://api.xyyxt.net/wx/pay/callback";

    private WXPayRequest wxPayRequest;

    private boolean autoReport = false;

    @Autowired
    private IOrderService iOrderService;

    @Autowired
    private IOrderPossessUserService iOrderPossessUserService;

    @Autowired
    private IOrderGoodsService iOrderGoodsService;

    @Autowired
    private IOrderCouponService iOrderCouponService;

    @Autowired
    private ICourseService iCourseService;

    @Autowired
    private IUserService iUserService;


    private String gzh_tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";

    private String gzh_tokenParam = "grant_type=client_credential&appid=%s&secret=%s";

    @Override
    public Map<String, String> payment(String out_trade_no,String openid,String body,String price) {
        WxSmallConfig config = new WxSmallConfig(appid,mchid,key);
        try {
            WXPay wxpay = new WXPay(config);
            Map<String, String> data = new HashMap<String, String>();
            data.put("body", body);
            data.put("out_trade_no", out_trade_no);
            data.put("device_info", "");
            data.put("fee_type", "CNY");
            data.put("total_fee", "1");
            data.put("openid", openid);
            data.put("spbill_create_ip", IpUtils.getIpAddr(ServletUtils.getRequest()));
            data.put("notify_url", notifyUrl);
            data.put("trade_type", "JSAPI");
            String TenantId = ServletUtils.getRequest().getHeader("TenantId");
            data.put("attach", TenantId);
            Map<String, String> resp = wxpay.unifiedOrder(data);

            Map<String, String> result = new HashMap<>();
   //         result.put("provider","wxpay");
            result.put("appId",appid);
            result.put("timeStamp",String.valueOf(DateUtils.getNowTime()));
            result.put("nonceStr",resp.get("nonce_str"));
            result.put("package","prepay_id="+resp.get("prepay_id"));
            result.put("signType","MD5");
            result.put("sign", WXPayUtil.generateSignature(result, key, WXPayConstants.SignType.MD5));
     //       System.out.println(resp);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public Map<String, String> paymentGzh(String out_trade_no, String openid, String body, BigDecimal price, String url) {
        WxSmallConfig config = new WxSmallConfig(gzhAppid,mchid,key);
        try {
            WXPay wxpay = new WXPay(config);
            BigDecimal unit = new BigDecimal(100);
            price = price.multiply(unit);
            Map<String, String> data = new HashMap<String, String>();
            data.put("body", body);
            data.put("out_trade_no", out_trade_no);
            data.put("device_info", "");
            data.put("fee_type", "CNY");
            data.put("total_fee", price.intValue()+"");
            data.put("openid", openid);
            data.put("spbill_create_ip", IpUtils.getIpAddr(ServletUtils.getRequest()));
            data.put("notify_url", notifyUrl);
            data.put("trade_type", "JSAPI");
            String TenantId = ServletUtils.getRequest().getHeader("TenantId");
            data.put("attach", TenantId);
            Map<String, String> resp = wxpay.unifiedOrder(data);
            Map<String, String> result = new HashMap<>();
            //         result.put("provider","wxpay");
            result.put("appId",gzhAppid);
            result.put("timeStamp",String.valueOf(DateUtils.getNowTime()));
            result.put("nonceStr",resp.get("nonce_str"));
            result.put("package","prepay_id="+resp.get("prepay_id"));
            result.put("signType","MD5");
            result.put("paySign", WXPayUtil.generateSignature(result, key, WXPayConstants.SignType.MD5));
            result.put("configPaySign", wx_config_sign(result,url));
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("错误"+e.getMessage());
        }

    //    return null;
    }

    public String wx_config_sign(Map<String, String> result,String url) {
        String jsapi_ticket = wx_get_jsapi_ticket();
        if(!Validator.isNotNull(jsapi_ticket)){
            throw new CustomException("jsapi_ticket错误"+jsapi_ticket);
        }
        String str = "jsapi_ticket="+jsapi_ticket+"&noncestr="+result.get("nonceStr")+"&timestamp="+result.get("timeStamp")+"&url="+url;
        String signature = AES.SHA1(str);
        return signature;
    }

    @Override
    public String paymentCallBack(String notifyData) {
        String xmlBack = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml> ";
        WxSmallConfig config = new WxSmallConfig(appid,mchid,key);
        try {
            WXPay wxpay = new WXPay(config);

            Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);  // 转换成map

            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
                String result_code = notifyMap.get("result_code");
                if("SUCCESS".equals(result_code)){
                    String out_trade_no = notifyMap.get("out_trade_no");
                    String transaction_id = notifyMap.get("transaction_id");
                    String TenantId = notifyMap.get("attach");
                    ServletUtils.getRequestAttributes().getResponse().setHeader("TenantId",TenantId);
                    if(dealOrder(out_trade_no,transaction_id)){
                        xmlBack = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
                        return xmlBack;
                    }
                }
            }
            else {
                // 签名错误，如果数据里没有sign字段，也认为是签名错误
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return xmlBack;
    }


    private boolean dealOrder(String out_trade_no,String transaction_id){
        Order order = iOrderService.queryByOrderSn(out_trade_no);
        if(order.getOrderStatus()==0){
            order.setOrderStatus(1);
            order.setPayTime(DateUtils.getNowTime());
            order.setTransid(transaction_id);
            order.setOrderGeneral(out_trade_no);
            if(iOrderService.updateById(order)){
                OrderGoodsQueryBo bo = new OrderGoodsQueryBo();
                bo.setOrderSn(out_trade_no);
                List<OrderGoodsVo> goodsList = iOrderGoodsService.queryList(bo);
                for (OrderGoodsVo g : goodsList) {
                    if(g.getGoodsType()==4){
                        //充值订单
                        BigDecimal unit = new BigDecimal(10000);
                        g.setGoodsPrice(g.getGoodsPrice().multiply(unit));
                        UpdateWrapper<User> updateUserWrapper = new UpdateWrapper<>();
                        updateUserWrapper.setSql("money = money +"+g.getGoodsPrice());
                        updateUserWrapper.eq("user_id", order.getUserId());
                        iUserService.update(updateUserWrapper);
                    }else{
                        //添加入我的学习
                        OrderPossessUserAddBo addBo = new OrderPossessUserAddBo();
                        addBo.setUserId(order.getUserId());
                        addBo.setPossessId(g.getGoodsId());
                        addBo.setTypeId(g.getGoodsType());
                        addBo.setSourceId(0);//订单来源
                        iOrderPossessUserService.insertByAddBo(addBo);
                    }
                }
                //用优惠券更新状态
                OrderCoupon orderCoupon = iOrderCouponService.queryBySn(out_trade_no);
                if(Validator.isNotNull(orderCoupon)){
                    UpdateWrapper<Course> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.setSql("user_status = "+1);
                    updateWrapper.eq("coupon_id", orderCoupon.getCouponId());
                    iCourseService.update(updateWrapper);
                }
               return true;
            }
        }
        return false;
    }

    public String wx_get_jsapi_ticket() {
        String key = "gzh_ticket";
        String ticket = redisCache.getCacheObject(key);
        if(!Validator.isNotNull(ticket)){
            String access_token = wx_get_token();
            String param = String.format("access_token=%s&type=jsapi", access_token);
            String resultString  = HttpUtils.sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket",param);
            JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
            ticket = String.valueOf(jsonObject.get("ticket"));
            if(ticket!=null){
                redisCache.setCacheObject(key, ticket, 2*50, TimeUnit.MINUTES);//2个小时
            }
        }
        return ticket;
    }

    //获取微信公众号access_token
    public String wx_get_token()
    {
        String key = "gzh_access_token";
        String access_token = redisCache.getCacheObject(key);
        if(!Validator.isNotNull(access_token)){
            String param = String.format(gzh_tokenParam, gzhAppid, gzh_appsrcret);
            String resultString  = HttpUtils.sendGet(gzh_tokenUrl,param);
            //解析json
            JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
            access_token = String.valueOf(jsonObject.get("access_token"));  //这里应该把access_token缓存起来，至于要怎么缓存就看各位了，有效期是7200s
            if(access_token!=null){
                redisCache.setCacheObject(key, access_token, 2*50, TimeUnit.MINUTES);//2个小时
            }
        }
        if(!Validator.isNotNull(access_token)){
            throw new CustomException("access_token错误"+access_token);
        }
        return access_token;
    }
}
