package com.rf.psychological.wxpay.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.rf.psychological.base.rest.BaseController;
import com.rf.psychological.enums.UserRole;
import com.rf.psychological.group.service.GroupInfoService;
import com.rf.psychological.security.AesEncryptUtils;
import com.rf.psychological.security.SafetyProcess;
import com.rf.psychological.user.dao.model.OpenIdEntity;
import com.rf.psychological.user.dao.model.UserEntity;
import com.rf.psychological.user.service.OpenidService;
import com.rf.psychological.user.service.UserService;
import com.rf.psychological.utils.Constant;
import com.rf.psychological.utils.IPUtiles;
import com.rf.psychological.utils.JWTUtil;
import com.rf.psychological.utils.Result;
import com.rf.psychological.wxpay.config.WxPayConfig;
import com.rf.psychological.wxpay.service.WxPayService;
import com.rf.psychological.wxpay.utils.HttpUtils;
import com.rf.psychological.wxpay.utils.WechatPay2ValidatorForRequest;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:微信支付接口
 * @Author: zsf
 * @Date: 2022/6/21
 */
@CrossOrigin //跨域
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付APIv3")
@Slf4j
@ConditionalOnProperty(prefix="wx.pay",name = "is_lan", havingValue = "false")
public class WxPayController  extends BaseController {

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private WxPayConfig wxPayConfig;

    @Autowired
    private Verifier verifier;

    @Autowired
    private OpenidService openidService;
    @Resource
    private CloseableHttpClient wxPayClient;

    @Autowired
    private UserService userService;

    @Autowired
    private GroupInfoService groupInfoService;
    /**
     * 调用统一下单API，生成支付二维码
     * @return
     */
    @SafetyProcess
    @ApiOperation(value = "调用统一下单API，生成支付二维码",notes = "json字符串形式传参(加密)，" +
            "data参数中包括(必传)：productId:量表id,userId:用户id，resultId:测试结果id，description：订单描述信息，" +
            "total：订单总金额，单位为分;")
    @PostMapping("/native")
    public Result<Map<String,Object>> nativePay(@RequestBody String paramJson){
        try {
            log.info(paramJson);
            String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(paramJson).getString("data"));
            log.info(paramData);
            if (StringUtils.isEmpty(paramData)){
                return fail(null,"参数不能为空");
            }
            Map<String,Object> map = wxPayService.nativePay(JSON.parseObject(paramData));
            return success(map);
        }catch (Exception e){
            e.printStackTrace();
            return fail("二维码生成失败");
        }
    }

    /**
     * h5下单API，生成支付二维码
     * @return
     */
    @SafetyProcess
    @ApiOperation(value = "h5下单API，生成支付二维码",notes = "json字符串形式传参（加密），" +
            "data参数中包括(必传)：productId:量表id,userId:用户id，resultId:测试结果id，description：订单描述信息，" +
            "payerClientIp：用户的客户端IP，支持IPv4和IPv6两种格式的IP地址，sceneType：场景类型ios、Android，" +
            "total：订单总金额，单位为分")
    @PostMapping("/h5Pay")
    public Result h5Pay(@RequestBody String paramJson, HttpServletRequest request) throws Exception {
        try {
            String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(paramJson).getString("data"));
            log.info("paramData:"+paramData);
            if (StringUtils.isEmpty(paramData)){
                return fail(null,"参数不能为空");
            }
            //获取必要参数
            JSONObject paramObject = JSONObject.parseObject(paramData);
            //获取ip
            String payerClientIp = IPUtiles.getRealIp(request);
            paramObject.put("payerClientIp",payerClientIp);
            Map result = wxPayService.h5Pay(paramObject);
            return success(result);
        }catch (Exception e){
            e.printStackTrace();
            return fail("h5_url生成失败");
        }
    }

    @SafetyProcess
    @ApiOperation(value = "小程序预下单",notes = "参数同native下单")
    @PostMapping("/aspiPay")
    public Result aspiPay(@RequestBody String json){
        log.info("json请求参数：{}",json);
        try {
            String paramData = AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data"));
            if (StringUtils.isEmpty(paramData)){
                return fail(null,"参数不能为空");
            }
            //获取必要参数
            JSONObject paramObject = JSONObject.parseObject(paramData);
            if(!paramObject.containsKey("openId")||StringUtils.isBlank(paramObject.getString("openId"))){
               UserEntity userEntity = userService.findUserById(paramObject.getString("userId"));
                // OpenIdEntity openIdEntity = this.openidService.findByUserId(paramObject.getString("userId"));
                if(userEntity == null){
                    return fail("用户未登录");
                }
                paramObject.put("openId",userEntity.getPhone());
            }
            Map result = wxPayService.aspiPay(paramObject);
            return success(result);
        }catch (Exception e){
            e.printStackTrace();
            return fail("生成失败");
        }
    }

    /**
     * 支付通知 微信支付通过支付通知接口将用户支付成功消息通知给商户
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("支付通知")
    @PostMapping("/native/notify")
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("支付通知====================================================");
        Gson gson = new Gson();
        Map<String,Object> map = new HashMap<>();
        //处理通知参数
        try {
            String body = HttpUtils.readData( request);
            Map<String,Object> bodyMap = gson.fromJson(body, HashMap.class);
            String requestId = (String)bodyMap.get("id");
            log.info("支付通知的id ===> {}", requestId);
            log.info("支付通知的完整数据 ===> {}", body);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if(!wechatPay2ValidatorForRequest.validate(request)){

                log.error("通知验签失败");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return gson.toJson(map);
            }
            log.info("通知验签成功");
            //处理订单
            wxPayService.processOrder(bodyMap);

            //成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return gson.toJson(map);
        }catch (Exception e){
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return gson.toJson(map);
        }
    }


    /**
     * 用户取消订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @ApiOperation("用户取消订单-PC")
    @GetMapping("/cancel/{orderNo}")
    public Result cancel(@PathVariable String orderNo) throws Exception {
        log.info("取消订单");
        wxPayService.cancelOrder(orderNo);
        return success(null,"订单已取消");
    }


    @SafetyProcess
    @ApiOperation("查询订单")
    @GetMapping("/queryOrder/{orderNo}")
    public Result queryOrder(@PathVariable String orderNo) throws Exception {
        log.info("查询订单订单");
        return success( wxPayService.queryOrder(orderNo));
    }

    @ApiOperation("交易账单--暂未开发")
    @GetMapping("/queryTradeBill/{billDate}/{type}")
    public Result queryTradeBill(@PathVariable String billDate, @PathVariable String type){
        return success();
    }

    @GetMapping("/refund/{orderNo}")
    public Result refund(@PathVariable String orderNo) throws IOException {
        wxPayService.refund(orderNo);
        return success();
    }

//    @PostMapping("/code2openid")
//    @ApiOperation(value = "code 换 opernid",notes = "modelPhone：手机号；code：临时code，获取openid；petName：用户名")
//    @SafetyProcess
//    public Result<JSONObject> code2id(@RequestBody String json) throws Exception {
//        JSONObject resultJson = new JSONObject();
//        JSONObject data = JSONObject.parseObject(AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data")));
//        OpenIdEntity openIdEntity = this.openidService.findByPhone(data.getString("modelPhone"));
//        if(openIdEntity == null){
//            CloseableHttpResponse response = getToken(data.getString("code"));
//            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
//            String body = EntityUtils.toString(response.getEntity());
//            Gson gson = new Gson();
//            HashMap resultBody = gson.fromJson(body, HashMap.class);
//            if(statusCode == 200 || statusCode == 204){
//                openIdEntity = new OpenIdEntity();
//                openIdEntity.setOpenId((String) resultBody.get("openid"));
//                openIdEntity.setAuthType("vx");
//            }else{
//                log.error("获取openid失败：错误码 "+resultBody.get("errcode")+"  "+resultBody.get("errmsg"));
//                log.error("错误码：{}",resultBody.get("errcode"));
//                log.error("错误消息：{}",resultBody.get("errmsg"));
//                return fail();
//            }
//        }
//        //静默注册登录
//        UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(data.getString("modelPhone"), Constant.WEB_INSTITUTION_CODE, UserRole.COMMON.getType());
//        if(userEntity != null){
//            openIdEntity.setUserId(userEntity.getId());
//            openIdEntity.setPhone(data.getString("modelPhone"));
//            openIdEntity = this.openidService.save(openIdEntity);
//
//            if(StringUtils.isNotBlank(data.getString("petName"))&&(!userEntity.getPetName().equals(data.getString("petName")))){
//                userEntity.setPetName(data.getString("petName"));
//                this.userService.save(userEntity);
//            }
//            userEntity.setPassword("-");
//            resultJson.put("user", userEntity);
//            resultJson.put("type", userEntity.getRoleType());
//            resultJson.put("improve",false);
//        }else{
//            //注册
//            userEntity = new UserEntity();
//            userEntity.setPassword("-");
//            userEntity.setModelPhone(data.getString("modelPhone"));
//            userEntity.setGId(this.groupInfoService.findGroupByInstitutionNoAndName(Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_GROUP_NAME).getId());
//            userEntity.setInstitutionName(Constant.WEB_INSTITUTION_NAME);
//            userEntity.setInstitutionNo(Constant.WEB_INSTITUTION_CODE);
//            userEntity.setUserStatus(Constant.USER_STATUS_NORMAL);
//            userEntity.setBirthday("-");
//            userEntity.setGender("-");
//            userEntity.setPetName(data.getString("petName"));
//            userEntity.setProfession("-");
//            userEntity.setAdditionInfo("微信小程序注册用户");
//            userEntity.setPhone(data.getString("modelPhone"));
//            userEntity.setRoleType(UserRole.COMMON.getType());
//            userEntity = this.userService.save(userEntity);
//            resultJson.put("improve",true);
//            //保存三方授权信息 openid
//            openIdEntity.setUserId(userEntity.getId());
//                openIdEntity.setPhone(data.getString("modelPhone"));
//            openIdEntity = this.openidService.save(openIdEntity);
//            //登录
////            TODO 将登录用户放入redis已登录用户信息，统计在线人数
//        }
//
//        resultJson.put("token", JWTUtil.getTokenByUserInfo(userEntity));
//        resultJson.put("user",userEntity);
//        resultJson.put("type",userEntity.getRoleType());
//        resultJson.put("openId",openIdEntity);
//        log.info("响应消息："+resultJson.toJSONString());
//        return success(resultJson);
//    }


    @PostMapping("/code2openid2")
    @ApiOperation(value = "code 换 opernid",notes = "code：临时code，获取openid；petName：用户名")
    @SafetyProcess
    public Result<JSONObject> code2openid2(@RequestBody String json) throws Exception {
        JSONObject resultJson = new JSONObject();
        JSONObject data = JSONObject.parseObject(AesEncryptUtils.decrypt(JSONObject.parseObject(json).getString("data")));
        String openId;
        CloseableHttpResponse response = getToken(data.getString("code"));
            int statusCode = response.getStatusLine().getStatusCode();//响应状态码
            String body = EntityUtils.toString(response.getEntity());
            Gson gson = new Gson();
            HashMap resultBody = gson.fromJson(body, HashMap.class);
            if(statusCode == 200 || statusCode == 204){
                openId = (String) resultBody.get("openid");
            }else{
                log.error("获取openid失败：错误码 "+resultBody.get("errcode")+"  "+resultBody.get("errmsg"));
                log.error("错误码：{}",resultBody.get("errcode"));
                log.error("错误消息：{}",resultBody.get("errmsg"));
                return fail();
            }
        //静默注册登录
        UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(openId, Constant.WEB_INSTITUTION_CODE, UserRole.COMMON.getType());
        if(userEntity != null){

//            if(StringUtils.isNotBlank(data.getString("petName"))&&(!userEntity.getPetName().equals(data.getString("petName")))){
//                userEntity.setPetName(data.getString("petName"));
//                this.userService.save(userEntity);
//            }
            userEntity.setPassword("-");
            resultJson.put("user", userEntity);
            resultJson.put("type", userEntity.getRoleType());
            resultJson.put("improve",false);
        }else{
            //注册
            userEntity = new UserEntity();
            userEntity.setPassword("-");
            userEntity.setGId(this.groupInfoService.findGroupByInstitutionNoAndName(Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_GROUP_NAME).getId());
            userEntity.setInstitutionName(Constant.WEB_INSTITUTION_NAME);
            userEntity.setInstitutionNo(Constant.WEB_INSTITUTION_CODE);
            userEntity.setUserStatus(Constant.USER_STATUS_NORMAL);
            userEntity.setBirthday("-");
            userEntity.setGender("-");
            userEntity.setPetName("微信用户");
            userEntity.setProfession("-");
            userEntity.setAdditionInfo("微信小程序注册用户");
            userEntity.setPhone(openId);
            userEntity.setRoleType(UserRole.COMMON.getType());
            userEntity = this.userService.save(userEntity);
            resultJson.put("improve",true);
            //登录
//            TODO 将登录用户放入redis已登录用户信息，统计在线人数
        }

        resultJson.put("token", JWTUtil.getTokenByUserInfo(userEntity));
        resultJson.put("user",userEntity);
        resultJson.put("type",userEntity.getRoleType());
        resultJson.put("openId",openId);
        log.info("响应消息："+resultJson.toJSONString());
        return success(resultJson);
    }

    @GetMapping("/getPhone/{code}")
    @SafetyProcess
    @ApiOperation(value = "获取用户手机号",notes = "code :临时code")
    public Result getPhone(@PathVariable String code) throws IOException {
//        1、获取access_token
        String access_token = wxPayService.getAccessToken();
//        2、获取用户手机号
        HashMap map = getPhoneNumber(code,access_token);
        int errcode = ((Number) map.get("errcode")).intValue();
        if(errcode == 0){
            //{"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"19138984495","purePhoneNumber":"19138984495","countryCode":"86","watermark":{"timestamp":1661308946,"appid":"wx2f422a2a1cb24c3c"}}}
            LinkedTreeMap map2 = (LinkedTreeMap) map.get("phone_info");
            String phoneNumber = String.valueOf(map2.get("phoneNumber"));
            if(StringUtils.isBlank(phoneNumber)){
                phoneNumber = String.valueOf(map2.get("purePhoneNumber"));
            }
            JSONObject resultJson = new JSONObject();
            resultJson.put("phone",phoneNumber);
            UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(phoneNumber,Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_VALUE_ONE);
            if(userEntity != null){
                resultJson.put("newer","0");
            }else {
                resultJson.put("newer","1");
            }
            return success(resultJson);
        }else if (errcode == -1){
            return fail("系统繁忙");
        }else if (errcode == 40029){
            log.info("code 不合法");
            return fail("获取手机号失败");
        }else {
            log.info("获取手机号失败错误码：{}，错误消息{}",errcode,map.get("errmsg"));
            return fail("获取手机号失败");
        }


    }


    /**
     * 获取
     * @param code
     * @param access_token
     * @return
     */
    private HashMap getPhoneNumber(String code, String access_token) throws IOException {
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+access_token;
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept", "application/json");
        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("code",code);
        Gson gson = new Gson();
        String jsonParams = gson.toJson(paramsMap);
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");
        CloseableHttpResponse response = wxPayClient.execute(httpPost);
        String body = EntityUtils.toString(response.getEntity());//获取响应体
        log.info("获取手机号：响应体{}",body);
        //响应结果
        return  gson.fromJson(body,HashMap.class);
    }

    /**
     * 获取access_token
     * @return
     * @throws IOException
     */
//    public String getAccessToken() throws IOException {
//        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+wxPayConfig.getAspi_appid()+"&secret="+wxPayConfig.getAspi_secret() ;
//        HttpGet httpGet = new HttpGet(url);
//        CloseableHttpResponse response = wxPayClient.execute(httpGet);
//        String body = EntityUtils.toString(response.getEntity());
//        Gson gson = new Gson();
//        HashMap resultBody = gson.fromJson(body, HashMap.class);
//        if(resultBody.containsKey("errcode")){
//            log.error("获取token异常：");
//            log.error("errcode："+resultBody.get("errcode"));
//            log.error("errmsg:"+resultBody.get("errmsg"));
//        }else{
//            return (String) resultBody.get("access_token");
//        }
//        return null;
//    }
    public CloseableHttpResponse getToken(String code) throws IOException {
        String url = wxPayConfig.getAspi_url() +
                "?appid=" + wxPayConfig.getAspi_appid() +
                "&secret=" + wxPayConfig.getAspi_secret() +
                "&js_code=" + code +
                "&grant_type=authorization_code";
        log.info("code2openid URL ："+url);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");
        return wxPayClient.execute(httpGet);
    }

    @GetMapping("/generateShortLink")
    @ApiOperation(value = "获取到分享链接",notes = "path:跳转路径和参数")
    public Result generateShortLink(@RequestParam String path,@RequestParam String query){
        try {
            if (StringUtils.isEmpty(path)){
                return fail(null,"参数不能为空");
            }
            String link = wxPayService.generateLink(path,query);
            return success(link);
        }catch (Exception e){
            e.printStackTrace();
            return fail("操作失败");
        }
    }

    @GetMapping("/generateWxCode")
    @SafetyProcess
    @ApiOperation(value = "获取到小程序",notes = "page:跳转路径scene参数envVersion环境")
    public Result generateWxCode(@RequestParam String page,@RequestParam String scene,@RequestParam(required = false) String envVersion){
        try {
            if (StringUtils.isEmpty(page)){
                return fail(null,"参数不能为空");
            }
            String link = wxPayService.generateWxCode(page,scene,envVersion);
            return success(link);
        }catch (Exception e){
            e.printStackTrace();
            return fail("操作失败");
        }
    }
}
