package com.mmc.iuav.user.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mmc.iuav.http.HttpHelper;
import com.mmc.iuav.http.HttpsRequestUtil;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.response.ResultEnum;
import com.mmc.iuav.user.constant.UserSystemConstant;
import com.mmc.iuav.user.constant.WxConstant;
import com.mmc.iuav.user.controller.wx.HttpsOpenUtil;
import com.mmc.iuav.user.dao.UserServiceDao;
import com.mmc.iuav.user.dao.UserSubInfoDao;
import com.mmc.iuav.user.entity.UserSubInfoDO;
import com.mmc.iuav.user.model.vo.AppletMsgVO;
import com.mmc.iuav.user.model.vo.WxLoginVO;
import com.mmc.iuav.user.model.vo.WxMsgVO;
import com.mmc.iuav.user.service.WxService;
import com.mmc.iuav.user.util.TDateUtil;
import com.mmc.iuav.user.util.WxApiUtil;
import com.mmc.iuav.user.util.XmlToMapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: zj
 * @Date: 2023/5/16 13:44
 */
@Service
@Slf4j
public class WxServiceImpl implements WxService {
    @Autowired
    private UserSystemConstant userSystemConstant;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserSubInfoDao userSubInfoDao;

    @Autowired
    private UserServiceDao userServiceDao;

    @Override
    public String appLogin(WxLoginVO wxLoginVO) {
        String url = WxConstant.CODE2_SESSION_URL + "?appid=" + userSystemConstant.getWxAppId() + "&secret=" +
                userSystemConstant.getWxAppSecret() + "&js_code=" + wxLoginVO.getCode() + "&grant_type=" + WxConstant.GRANT_TYPE;
        String data = HttpsRequestUtil.httpsGet(url, null);
        return data;
    }

    @Override
    public String pcLogin(WxLoginVO wxLoginVO) {
        String url = WxConstant.ACCESS_TOKEN_URL + "?appid=" + userSystemConstant.getWxAppId() + "&secret=" + userSystemConstant.getWxAppSecret() +
                "&code=" + wxLoginVO.getCode() + "&grant_type=" + WxConstant.GRANT_TYPE;
        String data = HttpsRequestUtil.httpsGet(url, null);
        return data;
    }

    @Override
    public String getAccessToken() {
        //token有效期为7200s，需要保存起来，先从redis中获取accessToken，没有则请求获取
        String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.IUAV_MINI_PROGRAM_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" +
                    userSystemConstant.getWxAppId() + "&secret=" + userSystemConstant.getWxAppSecret();
            String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null);
            JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg);
            if (accessTokenMsg.indexOf("access_token") == -1) {
                return null;
            }
            accessToken = tokenResult.getString("access_token");
            long expiresIn = tokenResult.getLong("expires_in");
            //保存进redis
            stringRedisTemplate.opsForValue().set(WxConstant.IUAV_MINI_PROGRAM_ACCESS_TOKEN, accessToken, expiresIn, TimeUnit.SECONDS);
            return accessToken;
        }
        return accessToken;
    }

    @Override
    public String getStableAccessToken() {
        //token有效期为7200s，需要保存起来，先从redis中获取accessToken，没有则请求获取
        String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.IUAV_MINI_PROGRAM_STABLE_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            Map<String, String> params = new HashMap<String, String>();
            params.put("grant_type", "client_credential");
            params.put("appid", userSystemConstant.getWxAppId());
            params.put("secret", userSystemConstant.getWxAppSecret());
            String stableAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/stable_token";
            String res = null;
            try {
                res = HttpsRequestUtil.httpsRequest(stableAccessTokenUrl, "POST", null, JSONObject.toJSONString(params));
            } catch (Exception e) {
                e.printStackTrace();
            }
            JSONObject tokenResult = JSONObject.parseObject(res);
            if (res.indexOf("access_token") == -1) {
                return null;
            }
            accessToken = tokenResult.getString("access_token");
            long expiresIn = tokenResult.getLong("expires_in");
            //保存进redis
            stringRedisTemplate.opsForValue().set(WxConstant.IUAV_MINI_PROGRAM_STABLE_ACCESS_TOKEN, accessToken, expiresIn, TimeUnit.SECONDS);
            return accessToken;
        }
        return accessToken;
    }

    @Override
    public String getSubAccessToken() {
        //token有效期为7200s，需要保存起来，先从redis中获取accessToken，没有则请求获取
        String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.SHARE_FLY_SUB_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            String getAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential" + "&appid=" +
                    userSystemConstant.getWxSubAppId() + "&secret=" + userSystemConstant.getWxSubSecret();
            String accessTokenMsg = HttpsRequestUtil.httpsGet(getAccessTokenUrl, null);
            JSONObject tokenResult = JSONObject.parseObject(accessTokenMsg);
            if (accessTokenMsg.indexOf("access_token") == -1) {
                log.info("获取公众号access_token有误：{}", tokenResult);
                return null;
            }
            accessToken = tokenResult.getString("access_token");
            long expiresIn = tokenResult.getLong("expires_in");
            //保存进redis
            stringRedisTemplate.opsForValue().set(WxConstant.SHARE_FLY_SUB_ACCESS_TOKEN, accessToken, expiresIn, TimeUnit.SECONDS);
            return accessToken;
        }
        return accessToken;
    }

    @Override
    public String getSubStableAccessToken() {
        //token有效期为7200s，需要保存起来，先从redis中获取accessToken，没有则请求获取
        String accessToken = stringRedisTemplate.opsForValue().get(WxConstant.SHARE_FLY_SUB_STABLE_ACCESS_TOKEN);
        if (StringUtils.isBlank(accessToken)) {
            Map<String, String> params = new HashMap<String, String>();
            params.put("grant_type", "client_credential");
            params.put("appid", userSystemConstant.getWxSubAppId());
            params.put("secret", userSystemConstant.getWxSubSecret());
            String res = null;
            try {
                res = HttpsRequestUtil.httpsRequest("https://api.weixin.qq.com/cgi-bin/stable_token", "POST", null, JSONObject.toJSONString(params));
            } catch (Exception e) {
                e.printStackTrace();
            }
            JSONObject tokenResult = JSONObject.parseObject(res);
            if (res.indexOf("access_token") == -1) {
                log.info("获取公众号access_token有误：{}", tokenResult);
                return null;
            }
            accessToken = tokenResult.getString("access_token");
            long expiresIn = tokenResult.getLong("expires_in");
            //保存进redis
            stringRedisTemplate.opsForValue().set(WxConstant.SHARE_FLY_SUB_STABLE_ACCESS_TOKEN, accessToken, expiresIn, TimeUnit.SECONDS);
            return accessToken;
        }
        return accessToken;
    }

    @Override
    public String receiveSubAccountEvents(HttpServletRequest request) {
        try {
            Map<String, String> map = this.convertRequestToMap(request);
            log.info("Received wx events(after convert)：{}", JSONObject.toJSONString(map));
            String event = map.get("Event");
            if (WxConstant.subscribe.equals(event)) {
                // 关注事件
                this.subScribeUser(map);
            } else if (WxConstant.unsubscribe.equals(event)) {
                // 取消关注事件
                String openId = map.get("FromUserName");
                userSubInfoDao.removeUserSubInfo(openId);
            }
        } catch (Exception e) {
            return "error";
        }
        return "success";
    }

    private void subScribeUser(Map<String, String> map) {
        String openId = map.get("FromUserName");
        Integer count = userSubInfoDao.countUserSubInfo(openId);
        if (count == 0) {
            UserSubInfoDO sub = new UserSubInfoDO();
            sub.setOpenId(openId);
            sub.setRegStatus(0);
            sub.setDeleted(0);
            sub.setCreateTime(new Date());
            userSubInfoDao.insertUserSubInfo(sub);
//            WxRequestVO wq = new WxRequestVO();
//            wq.setOpenId(sub.getOpenId());
//            publicsher.sendDirectWxRegUser(wq, RabbitMqConfig.USER_WX_ROUTING_KEY);
            this.updateWXUserInfo(openId);
        }
    }

    private Map<String, String> convertRequestToMap(HttpServletRequest request) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
        String line = "";
        StringBuffer buffer = new StringBuffer();
        while ((line = br.readLine()) != null) {
            buffer.append(line);
        }
        String notifyXml = buffer.toString();
        return XmlToMapUtil.xmlToMap(notifyXml);
    }

    private void updateWXUserInfo(String openid) {
        String accessToken = this.getSubAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            return;
        }
        try {
            String InfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid
                    + "&lang=zh_CN";
            String jsonStr = HttpsRequestUtil.httpsGet(InfoUrl, null);
            log.info("updateWXUserInfo：{}", jsonStr);
            JSONObject obj = JSONObject.parseObject(jsonStr);
            // 用户是否订阅该公众号标识，值为0时，代表此用户没有关注该公众号，拉取不到其余信息。
            Integer subscribe = obj.getInteger("subscribe");
            if (subscribe != null && subscribe == 1) {
                UserSubInfoDO user = new UserSubInfoDO();
                user.setOpenId(openid);
                user.setUnionId(obj.getString("unionid"));
                user.setNickName(obj.getString("nickname"));
                user.setRegStatus(1);
                userSubInfoDao.updateUserSubInfo(user);
                return;
            } else {
                log.info("未订阅公众号，无法拉取信息。");
                return;
            }
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }


    @Override
    public ResultBody sendSubTemplateMsg(WxMsgVO ws) {
        String accessToken = null;
        try {
            accessToken = this.getSubStableAccessToken();
            if (StringUtils.isBlank(ws.getTouser())) {
                String unionId = userServiceDao.getUserAccountById(ws.getUserAccountId()).getUnionId();// 查询对应的openId(touser)
                String touser = userSubInfoDao.getUserOpenidByUnionId(unionId);
                ws.setTouser(touser);
            }
            String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
            String param = ws.buildTemplateMsg();
            String result = HttpHelper.httpPost(url, param);
            log.info("模板消息发送结果：{}", result);
        } catch (Exception e) {
            log.error("accessToken获取失败:{}", e.getMessage());
            return ResultBody.error(ResultEnum.WX_ACCESS_TOKEN_ERROR.getResultCode(),
                    ResultEnum.WX_ACCESS_TOKEN_ERROR.getResultMsg() + e.getMessage());
        }
        return ResultBody.success();
    }

    @Override
    public ResultBody getUnLimitedQRCode(String path, String scene) {
        String base64 = "";
        try {
            String accessToken = this.getStableAccessToken();
            JSONObject param = new JSONObject();
            param.put("scene", scene);
            param.put("page", path);
            param.put("width", 430);
            param.put("check_path", false);
            param.put("env_version", userSystemConstant.getEnvVersion());
            String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
            //base64 = HttpHelper.httpPost(url, param.toJSONString());
            base64 = HttpsRequestUtil.getACodeBase64(url, "POST", null, param.toJSONString());
            return ResultBody.success(base64);
        } catch (Exception e) {
            return ResultBody.error(ResultEnum.APPLET_QR_CODE_CREATE_ERROR);
        }
    }

    @Override
    public ResultBody sendAppletMsg(AppletMsgVO appletMsgVO) {
        String accessToken = this.getStableAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            return ResultBody.error(ResultEnum.WX_ACCESS_TOKEN_ERROR.getResultCode(),
                    ResultEnum.WX_ACCESS_TOKEN_ERROR.getResultMsg());
        }
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
            appletMsgVO.setData(WxApiUtil.buildMsgJson(appletMsgVO.getData()));
            String param = JSONObject.toJSONString(appletMsgVO);
            HttpHelper.httpPost(url, param);
        } catch (Exception e) {
            log.error("系统异常：{}", e.getMessage());
        }
        return ResultBody.success();
    }

    @Override
    public String createUrlLink(String path, String query) {
        try {
            String accessToken = this.getStableAccessToken();
            JSONObject param = new JSONObject();
            param.put("path", path);
            param.put("env_version", userSystemConstant.getEnvVersion());
            param.put("query", query);
            String url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + accessToken;
            String res = HttpHelper.httpPost(url, param.toString());
            JSONObject result = JSONObject.parseObject(res);
            if (result.getString("errcode").equals("0")) {
                return result.getString("url_link");
            }
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String getUserPhoneNumber(Integer id, String code) {
        try {
            String accessToken = this.getStableAccessToken();
            JSONObject param = new JSONObject();
            param.put("code", code);
            String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
            String res = HttpHelper.httpPost(url, param.toString());
            JSONObject result = JSONObject.parseObject(res);
            log.info("param: id:{}，code:{}", id, code);
            log.info("getUserPhoneNumber: " + result.toString());
            if (result.getString("errcode").equals("0")) {
                String phone_info = result.getString("phone_info");
                JSONObject phoneInfoObject = JSONObject.parseObject(phone_info);
                return phoneInfoObject.getString("purePhoneNumber");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public ResultBody rid(String rid) throws Exception {
        JSONObject param = new JSONObject();
        param.put("rid", rid);
        String url = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=" + this.getSubAccessToken();
        String res = HttpHelper.httpPost(url, param.toString());
        return ResultBody.success(res);
    }

    @Override
    public ResultBody moveSubUserToTest() {
        String accessToken = this.getSubStableAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken;
        String jsonStr = HttpsRequestUtil.httpsGet(url, null);
        log.info("all users：{}", jsonStr);
        JSONObject obj = JSONObject.parseObject(jsonStr);
        List<String> lists = JSONArray.parseArray(obj.getJSONObject("data").get("openid").toString(), String.class);
        int count = 0;
        for (String openid : lists) {
            Integer integer = userSubInfoDao.countUserSubInfo(openid);
            if (integer == 0) {
                count++;
                UserSubInfoDO sub = new UserSubInfoDO();
                sub.setOpenId(openid);
                sub.setRegStatus(1);
                sub.setDeleted(0);
                sub.setCreateTime(new Date());
                userSubInfoDao.insertUserSubInfo(sub);
            }
        }
        log.info("User count: {}", count);
        return ResultBody.success();
    }

    @Override
    public ResultBody moveSubUserUnionIdToTest() {
        String accessToken = this.getSubStableAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken;
        String jsonStr = HttpsRequestUtil.httpsGet(url, null);
        log.info("all users：{}", jsonStr);
        JSONObject obj = JSONObject.parseObject(jsonStr);
        List<String> lists = JSONArray.parseArray(obj.getJSONObject("data").get("openid").toString(), String.class);
        int count = 0;
        for (String openid : lists) {
            UserSubInfoDO userSubInfo = userSubInfoDao.getUserSubInfo(openid);
            if (userSubInfo != null && userSubInfo.getUnionId() == null ) {
                String InfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid
                        + "&lang=zh_CN";
                String jsonStr1 = HttpsRequestUtil.httpsGet(InfoUrl, null);
                JSONObject obj1 = JSONObject.parseObject(jsonStr1);
                userSubInfo.setUnionId(obj1.getString("unionid"));
                userSubInfo.setRegStatus(1);
                userSubInfoDao.updateUserSubInfo(userSubInfo);
            }
        }
        log.info("User count: {}", count);
        return ResultBody.success();
    }
    @Override
    public ResultBody moveSubUser() {
        String accessToken = this.getSubStableAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken;
        String jsonStr = HttpsRequestUtil.httpsGet(url, null);
        log.info("all users：{}", jsonStr);
        JSONObject obj = JSONObject.parseObject(jsonStr);
        List<String> lists = JSONArray.parseArray(obj.getJSONObject("data").get("openid").toString(), String.class);
        int count = 0;
        for (String openid : lists) {
            Integer integer = userSubInfoDao.countUserSubInfo(openid);
            if (integer == 0) {
                count++;
                UserSubInfoDO sub = new UserSubInfoDO();
                sub.setOpenId(openid);
                sub.setRegStatus(1);
                sub.setDeleted(0);
                sub.setCreateTime(new Date());
                String InfoUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid
                        + "&lang=zh_CN";
                String jsonStr1 = HttpsRequestUtil.httpsGet(InfoUrl, null);
                JSONObject obj1 = JSONObject.parseObject(jsonStr1);
                sub.setUnionId(obj1.getString("unionid"));
                userSubInfoDao.insertUserSubInfo(sub);
            }
        }
        log.info("User count: {}", count);
        return ResultBody.success();
    }

    @Override
    public ResultBody getUserPortrait() {
        try {
            String accessToken = this.getStableAccessToken();
            com.alibaba.fastjson.JSONObject param = new com.alibaba.fastjson.JSONObject();

            String date = TDateUtil.getYesterdayDateByType("yyyyMMdd");
            param.put("begin_date", date);
            // param.put("env_version", UserSystemConstant.AppletEnv);
            param.put("end_date", date);
            param.put("access_token", accessToken);
            String url = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend?access_token=" + accessToken;
            String res = HttpsOpenUtil.httpSendPost(url, param.toJSONString());
            log.info("getUserPortrait: " + JSONObject.toJSONString(res));
            return ResultBody.success(res);
        } catch (Exception e) {
            return ResultBody.error(e.getMessage());
        }
    }
}
