package com.jpsoft.shinestar.modules.wechat.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.jpsoft.shinestar.config.WxConfig;
import com.jpsoft.shinestar.modules.base.entity.*;
import com.jpsoft.shinestar.modules.base.service.*;
import com.jpsoft.shinestar.modules.common.dto.MessageResult;
import com.jpsoft.shinestar.modules.common.service.impl.RedisServiceImpl;
import com.jpsoft.shinestar.modules.common.utils.*;
import com.jpsoft.shinestar.modules.common.utils.Generator.CaptchaUtilA;
import com.jpsoft.shinestar.modules.common.utils.Generator.CircleCaptchaA;
import com.jpsoft.shinestar.modules.pay.properties.WxPayProperties;
import com.jpsoft.shinestar.modules.sys.entity.User;
import com.jpsoft.shinestar.modules.sys.service.UserService;
import com.jpsoft.shinestar.modules.wechat.callback.EventCallback;
import com.jpsoft.shinestar.modules.wechat.entity.AccessControl;
import com.jpsoft.shinestar.modules.wechat.entity.AccessToken;
import com.jpsoft.shinestar.modules.wechat.entity.ReplyMessage;
import com.jpsoft.shinestar.modules.wechat.service.IAccessControlService;
import com.jpsoft.shinestar.modules.wechat.service.ReplyMessageService;
import com.jpsoft.shinestar.modules.wechat.vo.*;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 墨鱼_mo
 * @date 2019-12-3 15:08
 */

@Slf4j
@RequestMapping("/wechat")
@RestController
public class WxController {
    @Autowired
    private ApiUtil apiUtil;

    @Autowired
    private ParkApiUtil parkApiUtil;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    private WarningPusherService warningPusherService;

    @Autowired
    private ReplyMessageService replyMessageService;

    @Autowired
    private ValueOperations<String, Object> valueOperations;

    @Autowired
    private RedisServiceImpl redisService;

    @Autowired
    private OwnerInfoService ownerInfoService;

    @Autowired
    private WxPayProperties wxPayProperties;

    @Autowired
    private IAccessControlService accessControlService;

    @Autowired
    private InformationInfoService informationInfoService;

    @Autowired
    private CompanyInfoService companyInfoService;

    @Autowired
    private ParkingRecordService parkingRecordService;

    @Autowired
    private CompanyPaymentInfoService companyPaymentInfoService;

    @Autowired
    private ParkingDeviceService parkingDeviceService;

    @Autowired
    private PersonInfoService personInfoService;

    @Autowired
    private ParkingMerchantService parkingMerchantService;

    @Autowired
    private UserService userService;

    @ApiOperation(value = "获取微信配置")
    @GetMapping(value = "/getConfig")
    public MessageResult getConfig(String url) {

        int code = 200;
        String message = "获取成功";
        Object data = "";
        boolean result = true;

        try {
            AccessToken token = WeixinUtil.getAccessToken(wxPayProperties.getAppId(), wxPayProperties.getAppSecret());

            Map<String, String> wxMap = Sign.sign(WeixinUtil.getJsAPI(token.getToken()), url);

            wxMap.put("appId", wxPayProperties.getAppId());

            log.warn(JSONObject.toJSONString(wxMap));

            HashMap<String, Object> dataMap = new HashMap<String, Object>();

            dataMap.put("wxConfig", wxMap);

            data = dataMap;
        } catch (Exception ex) {
            log.error(ex.getMessage(),ex);

            code = 500;
            result = false;
            message = "系统错误";
        }

        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "获取微信code")
    @PostMapping(value = "findWechatUrl")
    public MessageResult findWechatUrl(@RequestBody String url) {

        String newpath = WeixinUtil.getCodeRequest(wxPayProperties.getAppId(), url, "snsapi_userinfo");

        HashMap<String, Object> dataMap = new HashMap<String, Object>();

        dataMap.put("wechatUrl", newpath);

        return new MessageResult(true, "获取成功", dataMap, 200);
    }

    @ApiOperation(value = "获取公众号用户信息")
    @GetMapping(value = "findUserInfo/{code}")
    public MessageResult findUserInfo(@PathVariable String code) {
        try {
            log.warn("code=" + code);
            log.warn("appId=" + wxPayProperties.getAppId());
            log.warn("appSecret=" + wxPayProperties.getAppSecret());

            AccessToken at = WeixinUtil.getAccessToken(wxPayProperties.getAppId(), wxPayProperties.getAppSecret(), code);


            if (at != null && StringUtils.isNotBlank(at.getOpenid())) {
                String openId = at.getOpenid();
                System.out.println("openId:" + openId);

                UserInfo userInfo = WeixinUtil.getUserInfo(openId, at.getToken());

                HashMap<String, Object> dataMap = new HashMap<String, Object>();

                dataMap.put("userInfo", userInfo);

                return new MessageResult(true, "获取微信信息成功", userInfo, 200);

            } else {
                return new MessageResult(false, "获取微信信息失败", "", 400);
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            return new MessageResult(false, "系统错误", "", 500);
        }
    }

    @ApiOperation(value = "获取公众号用户信息")
    @GetMapping(value = "/findParkUserInfo")
    public MessageResult findParkUserInfo(String code,String companyInfoId) {
        try {
            System.out.println("获取微信用户openId");
            CompanyPaymentInfo companyPaymentInfo = companyPaymentInfoService.findByCompanyId(companyInfoId);


            AccessToken at = WeixinUtil.getAccessToken(companyPaymentInfo.getSubAppId(), companyPaymentInfo.getSubAppSecret(), code);

            if (at != null && StringUtils.isNotBlank(at.getOpenid())) {
                String openId = at.getOpenid();
                System.out.println("openId:" + openId);

                UserInfo userInfo = WeixinUtil.getUserInfo(openId, at.getToken());

                HashMap<String, Object> dataMap = new HashMap<String, Object>();

                dataMap.put("userInfo", userInfo);

                return new MessageResult(true, "获取微信信息成功", userInfo, 200);

            } else {
                return new MessageResult(false, "获取微信信息失败", "", 400);
            }

        } catch (Exception ex) {
            ex.printStackTrace();
            return new MessageResult(false, "系统错误", "", 500);
        }
    }

    @GetMapping(value = "getAppId/{id}")
    @ResponseBody
    public MessageResult getAppId(@PathVariable("id") String id) {

        int code = 200;
        String message = "获取成功";
        Object data = "";
        boolean result = true;

        try {

            HashMap<String, Object> wxMap = new HashMap<>();

            wxMap.put("appId", wxPayProperties.getAppId());

            HashMap<String, Object> dataMap = new HashMap<String, Object>();

            dataMap.put("wxConfig", wxMap);

            data = dataMap;

        } catch (Exception ex) {
            code = 500;
            message = "系统错误";
            result = false;
        }

        return new MessageResult(result, message, data, code);
    }

    @GetMapping(value = "/findAccessControlByOpenId/{openId}")
    @ResponseBody
    public MessageResult findAccessControlByOpenId(@PathVariable(name = "openId", value = "") String openId) {

        int code = 200;
        String message = "查询成功";
        Object data = "";
        boolean result = true;

        if (StringUtils.isNotBlank(openId)) {

            AccessControl accessControl = accessControlService.findByOpenId(openId);

            if (accessControl == null) {
                code = 400;
                message = "用户信息不存在";
                result = false;
            } else {
                OwnerInfo ownerInfo = ownerInfoService.get(accessControl.getOwnerId());
                AccessControlVo accessControlVo = new AccessControlVo();
                BeanUtils.copyProperties(accessControl, accessControlVo);
                accessControlVo.setName(ownerInfo.getName());
                accessControlVo.setPhoneNum(ownerInfo.getTel());


                HashMap<String, Object> dataMap = new HashMap<String, Object>();

                dataMap.put("accessControl", accessControlVo);

                data = dataMap;
            }


        } else {
            code = 400;
            message = "用户信息不存在";
            result = false;

        }

        return new MessageResult(result, message, data, code);
    }


    @ApiOperation(value = "获取门禁token")
    @PostMapping("/getApiToken")
    public MessageResult getApiToken() {
        boolean result = true;
        String message = "";
        Object data = "";

        try {

            String token = apiUtil.getApiToken();
            if (StringUtils.isNotBlank(token)) {
                result = true;
                message = "获取token成功";
                redisService.put("apiToken", "apiToken", token, 7200L);
            }


        } catch (Exception e) {
            e.printStackTrace();
            result = false;
            message = "获取token失败";
        }

        return new MessageResult(result, message, data, 200);
    }

    @ApiOperation(value = "公众号开门")
    @GetMapping(value = "/openDoor/{openId}")
    public MessageResult openDoor(@PathVariable(name = "openId", value = "") String openId) {

        int code = 200;
        String message = "开锁成功";
        Object data = "";

        if (StringUtils.isNotBlank(openId)) {
            AccessControl accessControl = accessControlService.findByOpenId(openId);
            if (accessControl == null) {
                code = 401;
                message = "请先绑定用户";
            } else {


                String apiToken = (String) redisService.get("apiToken", "apiToken");

                if (!apiUtil.testApiToken(apiToken, "215301")) {
                    apiToken = apiUtil.getApiToken();
                }
                JSONObject resultJSON = apiUtil.httpRequest("https://api.parkline.cc/api/devicecgi", apiToken, "01", "215301", "01", "", "");
                String resultCode = resultJSON.getString("code");


                if (!resultCode.equals("0")) {
                    code = Integer.parseInt(resultCode);
                    message = resultJSON.getString("msg");
                }
            }


        } else {
            code = 400;
            message = "开锁失败";
        }

        return new MessageResult(true, message, "", code);
    }


    @ApiOperation(value = "获取图片验证码信息")
    @GetMapping("/getVerifyPic")
    public MessageResult getVerifyPic(String openId, HttpServletResponse response) {
        int code = 200;
        String message = "获取验证码成功";
        Object data = "";
        boolean result = true;

        try {

            if (StringUtils.isBlank(openId)) {
                throw new Exception("openId为空");
            }

            CircleCaptchaA captcha = CaptchaUtilA.createCircleCaptcha(200, 100, 4, 0);
            captcha.write(response.getOutputStream());
            String verifyPic = captcha.getCode();
            redisService.put("code", openId, verifyPic, 120);


            response.getOutputStream().close();

        } catch (Exception e) {
            e.printStackTrace();
            code = 500;
            message = e.getMessage();
            result = false;
        }

        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "获取短信验证码")
    @PostMapping("/getVerifyCode")
    public MessageResult getVerifyCode(@RequestBody BindPhoneVo bindPhoneVo) {
        int code = 200;
        String message = "获取验证码成功";
        Object data = "";
        boolean result = true;

        try {

            if (StringUtils.isBlank(bindPhoneVo.getOpenId())) {
                throw new Exception("openId为空");
            }


            if (StringUtils.isBlank(bindPhoneVo.getName()) || StringUtils.isBlank(bindPhoneVo.getPhoneNum())) {
                throw new Exception("业主姓名和手机号必填");
            }
            if (StringUtils.isBlank(bindPhoneVo.getVerifyPicCode())) {
                throw new Exception("图片验证码为空");
            }

            String verifyPicCode = (String) redisService.get("code", bindPhoneVo.getOpenId());
            if (StringUtils.isBlank(verifyPicCode)) {
                throw new Exception("图片验证码过期");
            }
            if (!verifyPicCode.equals(bindPhoneVo.getVerifyPicCode())) {
                throw new Exception("图片验证码错误");
            }


            List<Map> ownerInfoList = ownerInfoService.findByTel(bindPhoneVo.getPhoneNum());
            if (ownerInfoList.size() <= 0) {
                throw new Exception("人员信息未录入，请联系物业公司");
            }
            AccessControl accessControl = accessControlService.findByOwnerId(ownerInfoList.get(0).get("id").toString());


            if (accessControl != null) {
                throw new Exception("此手机号已被绑定");
            }


            String apiToken = (String) redisService.get("apiToken", "apiToken");

            if (!apiUtil.testApiToken(apiToken, "215301")) {
                apiToken = apiUtil.getApiToken();
            }
            JSONObject resultJSON = apiUtil.httpRequest("https://api.parkline.cc/api/facecgi", apiToken, "101", "", "", bindPhoneVo.getPhoneNum(), "");
            if (!resultJSON.getString("code").equals("100101")) {
                code = resultJSON.getIntValue("code");
                if (code == 100100) {
                    message = "未找到业主信息，请联系物业";
                } else {
                    message = resultJSON.getString("msg");
                }

                return new MessageResult(result, message, data, code);
            } else {
                JSONObject dataJSON = resultJSON.getJSONObject("data");
                String name = dataJSON.getString("name");
                if (!bindPhoneVo.getName().equals(name)) {
                    throw new Exception("业主姓名有误");
                }
            }

            String verifyCode = SMSUtil.generateNumberString(6);
            JSONObject verifyCodeJSON = new JSONObject();
            verifyCodeJSON.put("code", verifyCode);
            MessageResult rmg = SMSUtil.send(bindPhoneVo.getPhoneNum(), "SMS_49390047", verifyCodeJSON.toString());

            if (rmg.isResult()) {

                redisService.put("code", bindPhoneVo.getPhoneNum(), verifyCode, 120);

            }


        } catch (Exception e) {
            e.printStackTrace();
            code = 400;
            message = e.getMessage();
            result = false;
        }

        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "管理员绑定微信openid")
    @PostMapping(value = "/bindWechat")
    public MessageResult<String> bindWechat(String eventKey,String openId){
        MessageResult<String> messageResult = new MessageResult<>();

        try{
            String[] arr = eventKey.split(",");

            String userId = arr[1];
            User user = userService.get(userId);

            if (user!=null) {
                user.setOpenId(openId);
                user.setUpdateTime(new Date());
                user.setUpdateBy(userId);
                userService.update(user);
            }
            else{
                throw new Exception("用户不存在!");
            }

            messageResult.setMessage(user.getUserName() + "绑定微信成功!");
            messageResult.setResult(true);
        }
        catch (Exception ex){
            messageResult.setResult(false);
            messageResult.setMessage(ex.getMessage());

            log.error(ex.getMessage(),ex);
        }

        return messageResult;
    }

    @ApiOperation(value = "用户绑定微信openid")
    @PostMapping(value = "/bindPersonWechat")
    public MessageResult<String> bindPersonWechat(String eventKey,String openId){
        MessageResult<String> messageResult = new MessageResult<>();

        try{
            String[] arr = eventKey.split(",");

            String personId = arr[1];
            String phone = arr[2];

            PersonInfo person = personInfoService.get(Long.valueOf(personId));

            //多传一个电话号码避免，测试环境和正式环境混淆
            if (person!=null) {
                if(person.getPhone().equals(phone)) {
                    person.setOpenId(openId);
                    person.setUpdateTime(new Date());
                    person.setUpdateBy(personId);
                    personInfoService.update(person);
                }
                else{
                    throw new Exception("用户手机号错误!");
                }
            }
            else{
                throw new Exception("用户不存在!");
            }

            messageResult.setMessage(person.getName() + "绑定微信成功!");
            messageResult.setResult(true);
        }
        catch (Exception ex){
            messageResult.setResult(false);
            messageResult.setMessage(ex.getMessage());

            log.error(ex.getMessage(),ex);
        }

        return messageResult;
    }

    @ApiOperation(value = "公众号绑定住户手机")
    @PostMapping(value = "/bindPhoneNumAndOpenId")
    public MessageResult bindPhoneNumAndOpenId(@RequestBody BindPhoneVo bindPhoneVo) {

        int code = 200;
        String message = "绑定成功";
        Object data = "";
        boolean result = true;

        try {


            if (StringUtils.isBlank(bindPhoneVo.getPhoneNum()) || StringUtils.isBlank(bindPhoneVo.getOpenId()) || StringUtils.isBlank(bindPhoneVo.getVerifyCode())) {
                throw new Exception("参数错误");
            }

            //   else {


            String verifyCode = (String) redisService.get("code", bindPhoneVo.getPhoneNum());
            if (StringUtils.isBlank(verifyCode)) {
                throw new Exception("验证码过期");
            }
            if (!verifyCode.equals(bindPhoneVo.getVerifyCode())) {
                throw new Exception("验证码错误");
            }


            AccessControl accessControl1 = accessControlService.findByOpenId(bindPhoneVo.getOpenId());
            if (accessControl1 != null) {
                throw new Exception("此微信号已绑定手机号");
            }


            String apiToken = (String) redisService.get("apiToken", "apiToken");

            if (!apiUtil.testApiToken(apiToken, "215301")) {
                apiToken = apiUtil.getApiToken();
            }

            JSONObject resultJSON = apiUtil.httpRequest("https://api.parkline.cc/api/facecgi", apiToken, "101", "", "", bindPhoneVo.getPhoneNum(), "");
            if (!resultJSON.getString("code").equals("100101")) {
                code = resultJSON.getIntValue("code");
                System.out.println(code);
                if (code == 100100) {
                    message = "未找到业主信息，请联系物业";
                } else {
                    message = resultJSON.getString("msg");
                }
            } else {
                net.sf.json.JSONObject dataJSON = net.sf.json.JSONObject.fromObject(resultJSON.getString("data"));
                List<Map> ownerInfoList = ownerInfoService.findByTel(bindPhoneVo.getPhoneNum());
                AccessControl accessControl2 = new AccessControl();
                accessControl2.setId(UUID.randomUUID().toString());
                accessControl2.setOwnerId(ownerInfoList.get(0).get("id").toString());
                accessControl2.setOpenId(bindPhoneVo.getOpenId());
                accessControl2.setBindTime(new Date());
                accessControl2.setBindFace(false);
                accessControl2.setCreateTime(new Date());
                accessControlService.save(accessControl2);
            }


            //    }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            code = 400;
            message = e.getMessage();
            result = false;

        }


        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "微信端上传住户人脸")
    @PostMapping(value = "/bindFace")
    public MessageResult bindFace(@RequestBody BindFaceVo bindFaceVo) {

        int code = 200;
        String message = "提交成功";
        Object data = "";
        boolean result = true;


        List<Map> ownerList = ownerInfoService.findByTel(bindFaceVo.getPhoneNum());
        if (ownerList.size() <= 0) {
            return new MessageResult(false, "未找到用户信息，请联系物业", data, 400);
        }

        AccessControl accessControl = accessControlService.findByOwnerId(ownerList.get(0).get("id").toString());
        if (accessControl == null) {
            return new MessageResult(false, "请先进行微信绑定", data, 400);
        }

        if (StringUtils.isBlank(bindFaceVo.getPhoneNum()) || StringUtils.isBlank(bindFaceVo.getFiledata())) {
            code = 400;
            message = "参数错误";
            return new MessageResult(false, message, data, code);
        }

        String apiToken = (String) redisService.get("apiToken", "apiToken");

        if (!apiUtil.testApiToken(apiToken, "215301")) {
            apiToken = apiUtil.getApiToken();
        }

        JSONObject resultJSON = apiUtil.httpRequest("https://api.parkline.cc/api/facecgi", apiToken, "300", "215301", "01", bindFaceVo.getPhoneNum(), bindFaceVo.getFiledata());
        System.out.println("返回码：" + resultJSON.getInteger("code") + "-------------");
        if (!resultJSON.getString("code").equals("100101")) {
            code = resultJSON.getInteger("code");
            if (code == 100100) {
                message = "未找到业主信息，请联系物业";
            } else {
                message = resultJSON.getString("msg");
            }


        } else if (resultJSON.getString("code").equals("1")) {
            accessControl.setBindFace(true);
            accessControlService.update(accessControl);
        }
        return new MessageResult(result, message, "", code);
    }

    @ApiOperation(value = "微信端报修或投诉列表")
    @PostMapping(value = "/reportAndRepairsList")
    @ResponseBody
    public MessageResult reportAndRepairsList(@RequestBody RepairsVo repairsVo) {

        int code = 200;
        String message = "查询成功";
        Object data = "";
        boolean result = true;

        if (StringUtils.isBlank(repairsVo.getOpenId())) {
            code = 400;
            message = "openId为空";
            return new MessageResult(false, message, "", code);
        }
        if (repairsVo.getType() == null) {
            return new MessageResult(false, "类型不能为空", "", 400);
        }

        AccessControl accessControl = accessControlService.findByOpenId(repairsVo.getOpenId());
        if (accessControl == null) {
            return new MessageResult(false, "此微信还未绑定住户", "", 400);
        }
        List<InformationInfo> informationInfoList = informationInfoService.findByOwnerIdAndType(accessControl.getOwnerId(), repairsVo.getType());

        data = informationInfoList;


        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "微信端提交报修或投诉")
    @PostMapping(value = "/reportAndRepairs")
    @ResponseBody
    public MessageResult reportAndRepairs(@RequestBody RepairsVo repairsVo) {

        int code = 200;
        String message = "提交成功";
        Object data = "";
        boolean result = true;

        try {


            if (StringUtils.isBlank(repairsVo.getOpenId()) || StringUtils.isBlank(repairsVo.getContent())) {
                throw new Exception("参数错误");
            }
            if (repairsVo.getType() == null) {
                throw new Exception("类型不能为空");
            }

            AccessControl accessControl = accessControlService.findByOpenId(repairsVo.getOpenId());
            if (accessControl == null) {
                throw new Exception("此微信还未绑定住户");
            }
            InformationInfo informationInfo = new InformationInfo();
            informationInfo.setId(UUID.randomUUID().toString());
            informationInfo.setDelFlag(false);
            informationInfo.setCreateBy(repairsVo.getOpenId());
            informationInfo.setCreateTime(new Date());
            informationInfo.setStatus("0");
            informationInfo.setContent(repairsVo.getContent());
            //informationInfo.setOwnerId(accessControl.getOwnerId());
            informationInfo.setType(repairsVo.getType());

            informationInfoService.insert(informationInfo);

        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(), e);
            message = e.getMessage();
            result = false;
            code = 400;

        }
        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "根据报修或投诉id获取内容")
    @GetMapping(value = "/reportAndRepairsDetail")
    @ResponseBody
    public MessageResult reportAndRepairsDetail(String id) {

        int code = 200;
        String message = "查询成功";
        Object data = "";
        boolean result = true;

        try {


            if (id == null) {
                throw new Exception("id为空");
            }


            InformationInfo informationInfo = informationInfoService.get(id);
            data = informationInfo;


        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(), e);
            message = e.getMessage();
            code = 400;
            result = false;
        }
        return new MessageResult(result, message, data, code);
    }

    @ApiOperation(value = "验证服务器地址的有效性")
    @GetMapping("/get")
    @ResponseBody
    public String index(@RequestParam(defaultValue = "") String signature,
                        @RequestParam(defaultValue = "") String timestamp,
                        @RequestParam(defaultValue = "") String nonce,
                        @RequestParam(defaultValue = "") String echostr) {
        log.warn("signature=" + signature);
        log.warn("timestamp=" + timestamp);
        log.warn("nonce=" + nonce);
        log.warn("echostr=" + echostr);

        if (WeixinUtil.checkSignature(wxConfig.getToken(), signature, timestamp, nonce)) {
            return echostr;
        } else {
            return "index";
        }
    }


    @ResponseBody
    @ApiOperation(value = "创建二维码")
    @PostMapping("/qrcode/create")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "expire_seconds", paramType = "query", required = true, value = "该二维码有效时间，以秒为单位。 最大不超过2592000（即30天），此字段如果不填，则默认有效期为30秒。"),
            @ApiImplicitParam(name = "action_name", paramType = "query", required = true, value = "二维码类型，QR_SCENE为临时的整型参数值，QR_STR_SCENE为临时的字符串参数值，QR_LIMIT_SCENE为永久的整型参数值，QR_LIMIT_STR_SCENE为永久的字符串参数值"),
            @ApiImplicitParam(name = "scene_id", paramType = "query", value = "场景值ID，临时二维码时为32位非0整型，永久二维码时最大值为100000（目前参数只支持1--100000）"),
            @ApiImplicitParam(name = "scene_str", paramType = "query", value = "场景值ID（字符串形式的ID），字符串类型，长度限制为1到64")
    })
    public cn.hutool.json.JSONObject createQrcode(@RequestParam(name = "expire_seconds", defaultValue = "300") long expireSeconds,
                                                  @RequestParam(name = "action_name", defaultValue = "QR_STR_SCENE") String actionName,
                                                  @RequestParam(name = "scene_id", required = false) String sceneId,
                                                  @RequestParam(name = "scene_str", required = false) String sceneStr) {
        cn.hutool.json.JSONObject resultObj = new cn.hutool.json.JSONObject();

        try {
            StringBuilder urlBuilder = new StringBuilder();
            AccessToken accessToken = WeixinUtil.getAccessToken(wxConfig.getAppId(), wxConfig.getAppSecret());

            urlBuilder.append(wxConfig.getCreateQrCodeUrl())
                    .append("?access_token=")
                    .append(URLEncoder.encode(accessToken.getToken(), "UTF-8"));

            cn.hutool.json.JSONObject jsonObject = new cn.hutool.json.JSONObject();
            jsonObject.put("expire_seconds", expireSeconds);
            jsonObject.put("action_name", actionName);

            cn.hutool.json.JSONObject actionInfo = new cn.hutool.json.JSONObject();
            cn.hutool.json.JSONObject scene = new cn.hutool.json.JSONObject();

            StringBuilder keyBuilder = new StringBuilder();

            keyBuilder.append(accessToken);

            if (StringUtils.isNotEmpty(sceneId)) {
                scene.put("scene_id", sceneId);
                keyBuilder.append(sceneId);
            }

            if (StringUtils.isNotEmpty(sceneStr)) {
                scene.put("scene_str", sceneStr);
                keyBuilder.append(sceneStr);
            }

            String qrcodeUrl = (String) valueOperations.get("QRCODE_" + keyBuilder.toString());

            if (StringUtils.isNotEmpty(qrcodeUrl)) {
                resultObj.put("data", qrcodeUrl);
                resultObj.put("result", true);
            } else {
                actionInfo.put("scene", scene);

                jsonObject.put("action_info", actionInfo);

                StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");

                entity.setContentType("application/json");//发送json数据需要设置contentType

                HttpPost httpPost = new HttpPost(urlBuilder.toString());
                CloseableHttpClient httpClient = HttpClientBuilder.create().build();

                httpPost.setEntity(entity);

                HttpResponse res = httpClient.execute(httpPost);

                if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    String content = EntityUtils.toString(res.getEntity());// 返回json格式：
                    cn.hutool.json.JSONObject ret = new cn.hutool.json.JSONObject(content);

                    if (ret.containsKey("errcode")) {
                        resultObj.put("result", false);
                        resultObj.put("message", ret.getStr("errmsg"));
                        resultObj.put("code", ret.getInt("errcode"));
                    } else {
                        String ticket = ret.getStr("ticket");
                        long expire_seconds = ret.getLong("expire_seconds");

                        qrcodeUrl = wxConfig.getShowQrCodeUrl() + "?ticket=" + URLEncoder.encode(ticket, "UTF-8");

                        valueOperations.set("QRCODE_" + keyBuilder, qrcodeUrl, expire_seconds - 5, TimeUnit.SECONDS);

                        resultObj.put("data", qrcodeUrl);
                        resultObj.put("result", true);
                    }
                } else {
                    resultObj.put("result", false);
                    resultObj.put("message", "weixin服务器未正常返回!");
                }
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            resultObj.put("message", ex.getMessage());
            resultObj.put("result", false);
        }

        return resultObj;
    }

    @ApiOperation(value = "处理消息事件")
    @PostMapping("/get")
    public void processEvent(HttpServletRequest request, HttpServletResponse response) {
        try {
            log.warn("收到post请求");

            cn.hutool.json.JSONObject requestJson = null;

            if ("json".equals(wxConfig.getContentType())) {
                String jsonStr = new BufferedReader(new InputStreamReader(request.getInputStream()))
                        .lines().parallel().collect(Collectors.joining(System.lineSeparator()));

                requestJson = new cn.hutool.json.JSONObject(jsonStr);
            } else {
                requestJson = WeixinUtil.xmlToJson(request.getInputStream());
            }

            log.warn(requestJson.toString());

            response.setContentType("UTF-8");
            response.setContentType("text/html; charset=UTF-8");
            response.setCharacterEncoding("UTF-8");

            String event = requestJson.getStr("Event");
            String eventKey = requestJson.getStr("EventKey");

            /*
            正常扫码是："EventKey":"7000,2142006"；
            当未关注时，扫码是"EventKey":"qrscene_7000,2142006"
            */
            if (StringUtils.isNotEmpty(eventKey) && eventKey.indexOf("_") != -1) {
                String[] arr = eventKey.split("_");

                if (arr.length > 0) {
                    eventKey = arr[1];
                }
            }

            //微信公众号编号
            String wechatId = requestJson.getStr("ToUserName");
            //扫码用户openID
            String openId = requestJson.getStr("FromUserName");

            boolean processed = false;

            if (StringUtils.isNotEmpty(eventKey) && eventKey.indexOf(",") != -1) {
                String[] keys = eventKey.split(",");
                String eventCode = keys[0];
                String id = keys[1];

                ReplyMessage replyMessage = replyMessageService.findByEvent(eventCode);

                if (replyMessage != null) {
                    if (eventCode == "5000") {
                        WarningPusher warningPusher = warningPusherService.get(id);

                        if (warningPusher == null) {
                            WeixinUtil.replyTextMessage(response, wechatId, openId, "绑定信息不存在，请联系管理员");
                        } else if (StringUtils.isNotBlank(warningPusher.getOpenId())) {
                            WeixinUtil.replyTextMessage(response, wechatId, openId, "此二维码已被绑定，请联系管理员");
                        } else {
                            warningPusher.setOpenId(openId);
                            warningPusher.setUpdateTime(new Date());
                            warningPusherService.update(warningPusher);
                            WeixinUtil.replyTextMessage(response, wechatId, openId, replyMessage.getMessage());
                        }

                        processed = true;
                    }
                    else if ("4000".equals(eventCode)) {
                        CompanyInfo companyInfo = companyInfoService.get(id);
                        if (companyInfo == null) {
                            WeixinUtil.replyTextMessage(response, wechatId, openId, "您的公司暂时不在我们的管辖内，请联系管理员!");
                        } else {
                            WeixinUtil.replyArticlesMessage(response, wechatId, openId, companyInfo.getName(), replyMessage.getMessage(), companyInfo.getLogo(), "http://wisdomhousewechat.sudaonline.net/prevention-xxd/upyes.html");
                        }

                        processed = true;
                    }
                    else if("7000".equals(eventCode) || "7001".equals(eventCode)){
                        //微信扫码登录
                        callback(response, eventKey, wechatId, openId, replyMessage);

                        processed = true;
                    }
                    else if("8000".equals(eventCode) || "8001".equals(eventCode)){
                        //管理员绑定openid
                        callback(response, eventKey, wechatId, openId, replyMessage);

                        processed = true;
                    }
                    else if("9000".equals(eventCode) || "9001".equals(eventCode)){
                        //用户绑定openid
                        callback(response, eventKey, wechatId, openId, replyMessage);

                        processed = true;
                    }
                    else if("9080".equals(eventCode) || "9081".equals(eventCode)){
                        callback(response, eventKey, wechatId, openId, replyMessage);
                        processed = true;
                    }
                }
            }

            if (!processed) {
                String responseText = "success";

                if ("subscribe".equals(event)) {
                    ReplyMessage replyMessage = replyMessageService.findByEvent(event);

                    if (replyMessage != null) {
                        WeixinUtil.replyTextMessage(response, wechatId, openId, replyMessage.getMessage());
                    } else {
                        log.warn(openId + ",事件:" + event + "未设置自动回复!");
                        response.getWriter().print(responseText);
                    }
                    response.getWriter().print(responseText);
                } else {
                    response.getWriter().print(responseText);
                }
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);

            try {
                response.getWriter().print("fail");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void callback(HttpServletResponse response, String eventKey, String wechatId, String openId, ReplyMessage replyMessage) {
        EventCallback ecb = new EventCallback(replyMessage.getEvent(), replyMessage.getCallbackUrl());

        ecb.process(wechatId, openId, eventKey);

        //查看返回结果
        log.warn(ecb.getMessage());

        MessageResult<String> messageResult = JSONObject.parseObject(ecb.getMessage(), new TypeReference<MessageResult<String>>() {});

        WeixinUtil.replyTextMessage(response, wechatId, openId, messageResult.getMessage());
    }

    @GetMapping("/getMsgByCarNum")
    @ResponseBody
    @ApiOperation(value = "输入车牌号获取停车信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "companyInfoId", paramType = "query", required = true, value = "公司id"),
            @ApiImplicitParam(name = "carNum", paramType = "query", required = true, value = "车牌号"),
            @ApiImplicitParam(name = "deviceCode", paramType = "query", required = true, value = "默认设备编号"),
            @ApiImplicitParam(name = "openId", paramType = "query", required = false, value = "openId")

    })
    public MessageResult getMsgByCarNum(String companyInfoId, String carNum,String deviceCode,String openId) {
        int code = 200;
        String message = "查询成功";
        Object data = "";
        boolean result = true;

        HashMap<String, Object> dataMap = new HashMap<>();
        try {
            if (StringUtils.isNotBlank(carNum) && StringUtils.isBlank(deviceCode)){
                return new MessageResult(false, "功能未开放，请在出口扫码", "", 400);
            }

            if (StringUtils.isBlank(openId)){
                throw new Exception("获取用户信息失败");
            }



            if (StringUtils.isBlank(companyInfoId)) {
                return new MessageResult(false, "公司为空", "", 400);
            }
            CompanyInfo companyInfo = companyInfoService.get(companyInfoId);
            if (companyInfo == null) {
                return new MessageResult(false, "公司不存在", "", 400);
            }

            if (StringUtils.isBlank(carNum)) {
                return new MessageResult(false, "车牌号为空", "", 400);
            }
            ParkingDevice parkingDevice = parkingDeviceService.findByParkDeviceNo(deviceCode);

            String accessToken = (String) redisService.get("accessToken", parkingDevice.getKey());
            if (StringUtils.isBlank(accessToken)) {
                accessToken = parkApiUtil.getXToken(parkingDevice);
            }

            HashMap<String, Object> map = new HashMap<>();
            map.put("carNum", carNum);
            map.put("queryType", 1);
            net.sf.json.JSONObject jsonObject = parkApiUtil.httpRequest(parkingDevice,"/ipms/integration/kingdo/payment/info", accessToken, "POST", map);


            if (jsonObject.getString("errMsg").equals("success")) {



                net.sf.json.JSONObject dataJson = jsonObject.getJSONObject("data");
                if (dataJson.size()>0){


                BigDecimal parkingTime = new BigDecimal(dataJson.getString("parkTime"));
                Date inParkingTime = DateUtil.date(dataJson.getLong("inParkTime"));
                BigDecimal payAmount = new BigDecimal(dataJson.getString("receivableMoney"));
                String serialNumber = com.jpsoft.shinestar.modules.common.utils.StringUtils.getOutTradeNo();
                ParkingRecord parkingRecord = new ParkingRecord();
                parkingRecord.setId(UUID.randomUUID().toString());
                parkingRecord.setCarNum(carNum);
           //     parkingRecord.setCompanyId(companyInfoId);
                parkingRecord.setInParkingTime(inParkingTime);
                parkingRecord.setParkingTime(parkingTime);


             //   parkingRecord.setPayAmount(payAmount);
                parkingRecord.setPayAmount(payAmount);


                parkingRecord.setSerialNumber(serialNumber);
                parkingRecord.setPayStatus(10);
                parkingRecord.setProductTheme("停车费");
                parkingRecord.setOpenId(openId);
                parkingRecord.setCreateTime(new Date());
                parkingRecord.setDelFlag(false);
                parkingRecordService.insert(parkingRecord);

                HashMap<String, Object> parkMap = new HashMap<>();
                parkMap.put("carNum", carNum);
                parkMap.put("receivableMoney", parkingRecord.getPayAmount());
                parkMap.put("parkTime", TimeZonesUtil.parseSecond(dataJson.getLong("parkTime")));
                parkMap.put("inParkTime", DateUtil.formatDateTime(inParkingTime));
                parkMap.put("parkName",dataJson.getString("parkName"));


                dataMap.put("parkingData", parkMap);
                dataMap.put("parkingRecordId", parkingRecord.getId());

            }else {
                    return new MessageResult(false,"无停车信息","",400);
                }

            } else {
                code = 400;
                message = "查询失败";
                result = false;
                return new MessageResult(result, message, data, code);
            }


           /*HashMap<String,Object> map = new HashMap<>();
           map.put("carInNumPicUrl","http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-1.jpg");
           map.put("carInPicUrl", "http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-0.jpg");
           map.put("carNum",carNum);
           map.put("carType",1);
           map.put("inParkTime","2017-11-15");
           map.put("ownerType",0);
           map.put("parkCode","null_yu");
           map.put("parkName","yu");
           map.put("parkTime","1000");
           map.put("queryType",1);
           map.put("receivableMoney",0.01);*/

            //    data = map;


        } catch (Exception e) {
            e.printStackTrace();
            code = 400;
            message = "查询失败";
            result = false;
        }

        return new MessageResult(result, message, dataMap, code);
    }


    @GetMapping("/getMsgByDeviceCode")
    @ResponseBody
    @ApiOperation(value = "输入设备号获取停车信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "companyInfoId", paramType = "query", required = true, value = "公司id"),
            @ApiImplicitParam(name = "deviceCode", paramType = "query", required = true, value = "设备号"),
            @ApiImplicitParam(name = "openId", paramType = "query", required = false, value = "openId")

    })
    public MessageResult getMsgByDeviceCode(String companyInfoId,String deviceCode,String openId) {
        int code = 200;
        String message = "查询成功";
        Object data = "";
        boolean result = true;

        try {
//            if (StringUtils.isBlank(openId)){
//                throw new Exception("获取用户信息失败");
//            }


            if (StringUtils.isBlank(deviceCode)) {
                code = 400;
                message = "道闸设备编码为空";
                result = false;
                return new MessageResult(result, message, data, code);
            }
            ParkingDevice parkingDevice = parkingDeviceService.findByParkDeviceNo(deviceCode);
            if (parkingDevice == null){
                code = 400;
                message = "道闸设备未配置外网ip端口";
                result = false;
                return new MessageResult(result, message, data, code);
            }



            String accessToken = (String) redisService.get("accessToken", parkingDevice.getKey());
            if (StringUtils.isBlank(accessToken)) {
                accessToken = parkApiUtil.getXToken(parkingDevice);
            }

            HashMap<String, Object> map = new HashMap<>();
            map.put("deviceCode", deviceCode);
            net.sf.json.JSONObject jsonObject1 = parkApiUtil.httpRequest(parkingDevice,"/ipms/payment/bydevice", accessToken, "POST", map);


            //测试死数据，部署是删除
//            net.sf.json.JSONObject jsonObject1 = new net.sf.json.JSONObject();
//            jsonObject1.put("errMsg","success");
//            HashMap<String,Object> ceMap = new HashMap<>();
//            ceMap.put("carNumImgUrl","http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-1.jpg");
//            ceMap.put("carImgUrl", "http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-0.jpg");
//            ceMap.put("carNum","鄂D1234");
//            ceMap.put("carType",1);
//            ceMap.put("chargeDetail","停车时长42秒,收费金额0.01元");
//            ceMap.put("inParkTime",1586926518000L);
//            ceMap.put("ownerType",0);
//            ceMap.put("parkCode","null_yu");
//            ceMap.put("parkName","yu");
//            ceMap.put("parkTime",42);
//            ceMap.put("state",1);
//            ceMap.put("receivableMoney",0.01);
//            jsonObject1.put("data",ceMap);

            if (jsonObject1.getString("errMsg").equals("success")) {

                net.sf.json.JSONObject dataJson = (net.sf.json.JSONObject) jsonObject1.get("data");
                Integer state = dataJson.getInt("state");
                HashMap<String, Object> dataMap = new HashMap<>();
                if (dataJson.size()>0 && state ==1) {
                    System.out.println(dataJson.toString());

                    BigDecimal parkingTime = new BigDecimal(dataJson.getString("parkTime"));
                    Date inParkingTime = DateUtil.parse(dataJson.getString("inParkTime"));
                  //  Date inParkingTime = DateUtil.date(dataJson.getLong("inParkTime"));
                    BigDecimal payAmount = new BigDecimal(dataJson.getString("receivableMoney"));
                    String serialNumber = com.jpsoft.shinestar.modules.common.utils.StringUtils.getOutTradeNo();
                    ParkingRecord parkingRecord = new ParkingRecord();
                    parkingRecord.setId(UUID.randomUUID().toString());
                    parkingRecord.setCarNum(dataJson.getString("carNum"));
                //    parkingRecord.setParkingDeviceNo(deviceCode);
                //    parkingRecord.setCompanyId(companyInfoId);
                    parkingRecord.setInParkingTime(inParkingTime);
                    parkingRecord.setParkingTime(parkingTime);
                    parkingRecord.setPayAmount(payAmount);
                    parkingRecord.setSerialNumber(serialNumber);
                    parkingRecord.setPayStatus(10);
                    parkingRecord.setProductTheme("停车费");
                    parkingRecord.setOpenId(openId);
                    parkingRecord.setCreateTime(new Date());
                    parkingRecord.setDelFlag(false);
                    parkingRecordService.insert(parkingRecord);


                    HashMap<String, Object> parkMap = new HashMap<>();
                    parkMap.put("carNum", dataJson.getString("carNum"));
                    parkMap.put("receivableMoney", payAmount);
                    parkMap.put("parkTime", TimeZonesUtil.parseSecond(dataJson.getLong("parkTime")));
                    parkMap.put("inParkTime", DateUtil.formatDateTime(inParkingTime));
                    parkMap.put("parkName",dataJson.getString("parkName"));


                    dataMap.put("parkingData", parkMap);
                    dataMap.put("parkingRecordId", parkingRecord.getId());


                   /* dataMap.put("carNumImgUrl", dataJson.getString("carNumImgUrl"));
                    dataMap.put("carImgUrl", dataJson.getString("carImgUrl"));
                    dataMap.put("carNum", dataJson.getString("carNum"));
                    dataMap.put("carType", 1);
                    dataMap.put("chargeDetail", dataJson.getString("chargeDetail"));
                    dataMap.put("inParkTime", dataJson.getString("inParkTime"));
                    dataMap.put("ownerType", 0);
                    dataMap.put("parkCode", dataJson.getString("parkCode"));
                    dataMap.put("parkName", dataJson.getString("parkName"));
                    dataMap.put("parkTime", dataJson.getString("parkTime"));
                    dataMap.put("state", 1);
                    dataMap.put("receivableMoney", dataJson.getString("receivableMoney"));*/

                    data = dataMap;
                }else {
                    return new MessageResult(false, "无收费数据", data, 400);
                }


            } else {
                code = 400;
                message = "查询失败";
                result = false;
                return new MessageResult(result, message, data, code);
            }


           /* HashMap<String,Object> map = new HashMap<>();
            map.put("carNumImgUrl","http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-1.jpg");
            map.put("carImgUrl", "http://172.7.2.185:8082/d/1000033$1$0$0/20170629/10/2859-427-0.jpg");
            map.put("carNum","鄂D1234");
            map.put("carType",1);
            map.put("chargeDetail","停车时长42秒,收费金额0.01元");
            map.put("inParkTime","2017-11-15");
            map.put("ownerType",0);
            map.put("parkCode","null_yu");
            map.put("parkName","yu");
            map.put("parkTime","42");
            map.put("state",1);
            map.put("receivableMoney",0.01);

            data = map;*/


        } catch (Exception e) {
            e.printStackTrace();
            code = 500;
            message = "查询失败";
            result = false;
        }

        return new MessageResult(result, message, data, code);
    }



    @ApiOperation(value = "停车场商户绑定微信openid")
    @PostMapping(value = "/bindChannelWechat")
    public MessageResult<String> bindChannelWechat(String eventKey,String openId){
        MessageResult<String> messageResult = new MessageResult<>();

        try{
            String[] arr = eventKey.split(",");

            String merchantId = arr[1];

            ParkingMerchant parkingMerchant = parkingMerchantService.get(merchantId);

            if (parkingMerchant!=null) {
                String oldOpenId = parkingMerchant.getOpenId();
                if(StringUtils.isNotEmpty(oldOpenId)) {
                    //包含则不操作
                    if(!oldOpenId.contains(openId)) {
                        //不包含
                        parkingMerchant.setOpenId(oldOpenId + "," + openId);
                    }
                }else{
                    parkingMerchant.setOpenId(openId);
                }

                parkingMerchantService.update(parkingMerchant);
            }
            else{
                throw new Exception("商户不存在!");
            }
            messageResult.setMessage("绑定微信成功!");
            messageResult.setResult(true);
        }
        catch (Exception ex){
            messageResult.setResult(false);
            messageResult.setMessage(ex.getMessage());

            log.error(ex.getMessage(),ex);
        }

        return messageResult;
    }
}
