package vip.xiaonuo.biz.modular.api.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.modular.api.param.WechatTemplateMsg;
import vip.xiaonuo.biz.modular.api.param.WxUserMsgParam;
import vip.xiaonuo.biz.modular.oawxsendlog.entity.OaWxSendLog;
import vip.xiaonuo.biz.modular.oawxsendlog.service.OaWxSendLogService;
import vip.xiaonuo.biz.modular.officialinfo.entity.OfficialInfo;
import vip.xiaonuo.biz.modular.officialinfo.service.OfficialInfoService;
import vip.xiaonuo.biz.modular.utils.HttpClientUtil;
import vip.xiaonuo.biz.modular.utils.MsgUtil;
import vip.xiaonuo.biz.modular.utils.XmlUtil;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.prop.CommonProperties;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;

@Slf4j
@Service
public class ApiService {

    @Resource
    private OfficialInfoService officialInfoService;

    @Resource
    private CommonProperties commonProperties;
    @Resource
    private OaWxSendLogService oaWxSendLogService;

    public static JSONObject wx_token_map = new JSONObject();

    public void officialCallback(HttpServletRequest request, HttpServletResponse response) {
        // 响应消息
        PrintWriter out = null;
        String resMessage = "";
        try {
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
            //把微信返回的xml信息转义成map
            Map<String, Object> map = XmlUtil.parseXML(request.getInputStream());
            //消息来源用户标识
            String fromUserName = (String) map.get("FromUserName");
            //消息目的用户标识
            String toUserName = (String) map.get("ToUserName");
            //消息创建时间（整型）
            String createTime = (String) map.get("CreateTime");
            //消息类型
            String msgType = (String) map.get("MsgType");
            //事件类型：subscribe/unsubscribe
            String eventType = (String) map.get("Event");
            //如果为事件类型
            if (MsgUtil.MSGTYPE_EVENT.equals(msgType)) {
                //查询是否存在公众号表记录
                QueryWrapper<OfficialInfo> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(OfficialInfo::getOfficialOpenId, fromUserName)
                        .last("limit 1");
                OfficialInfo officialInfo = officialInfoService.getOne(queryWrapper);
                if (officialInfo == null) {
                    officialInfo = new OfficialInfo();
                    JSONObject jsonObject = this.getUserInfo(fromUserName);
                    if (jsonObject != null) {
                        officialInfo.setWxAddress(jsonObject.getString("country")
                                + jsonObject.getString("province")
                                + jsonObject.getString("city"));
                        officialInfo.setCreateTime(new Date());
                        officialInfo.setNickName(jsonObject.getString("nickname"));
                        officialInfo.setOfficialOpenId(jsonObject.getString("openid"));
                        officialInfo.setUnionId(jsonObject.getString("unionid"));
                        officialInfo.setWxHead(jsonObject.getString("headimgurl"));
                        officialInfoService.save(officialInfo);
                    }
                }
                //处理订阅事件-关注与取消关注
                if (MsgUtil.MESSAGE_SUBSCIBE.equals(eventType)) {
                    officialInfo.setStatus(1);
                    System.out.println("您好，谢谢您的关注！！");
                    if (ObjectUtil.isEmpty(officialInfo.getUnionId())) {
                        JSONObject jsonObject = this.getUserInfo(fromUserName);
                        if (jsonObject != null) {
                            officialInfo.setUnionId(jsonObject.getString("unionid"));
                        }
                    }
                    resMessage = MsgUtil.subscribeForText(toUserName, fromUserName, "您好，谢谢您的关注！！");
                } else if (MsgUtil.MESSAGE_UNSUBSCIBE.equals(eventType)) {//取消订阅
                    officialInfo.setStatus(0);
                    resMessage = MsgUtil.unsubscribeForText(toUserName, fromUserName, "取消关注~");
                }
                officialInfoService.updateById(officialInfo);
                log.info("eventType:" + eventType + ",fromUserName:" + fromUserName + ",toUserName:" + toUserName + ",msgType:" + msgType + ",createTime:" + createTime);
            }
            out = response.getWriter();
            out.println(resMessage);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("公众号回调异常------", e.getMessage());
            //itemErrorInfoService.errorAdd(e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }


    /**
     * 微信公众号的appid以及sercet
     * 获取微信用户信息
     * @param openId
     * @return
     */
    private JSONObject getUserInfo(String openId) {
        JSONObject jsonObject = null;
        String accessToken = getAccessToken(commonProperties.getOfficialAppId(), commonProperties.getOfficialSecret());
        log.info("-------openId：" + openId + "-------");
        log.info("-------accessToken：" + accessToken + "-------");
        StringBuffer url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/user/info");
        url.append("?access_token=").append(accessToken);
        url.append("&openid=").append(openId);
        url.append("&lang=zh_CN");

        String content = HttpUtil.get(url.toString());
        if (ObjectUtil.isNotEmpty(content)) {
            jsonObject = JSONObject.parseObject(content);
        }
        log.info("-------微信用户信息：" + content + "-------");
        return jsonObject;
    }


    private String getAccessToken(String sAppid, String sSecret) {
        // 因为微信有限制次数跟有效期，所以需要存在redis中
        if (wx_token_map.size() == 0) {
            wx_token_map.put("token", null);
        }
        String token = wx_token_map.getString("token");
        // token失效或者为空
        if (StrUtil.isEmpty(token) || "null".equals(token)) {
            StringBuffer url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/token");
            url.append("?grant_type=client_credential");
            url.append("&appid=").append(sAppid);
            url.append("&secret=").append(sSecret);
            log.info(url.toString());
            String content = HttpUtil.get(url.toString());
            if (StrUtil.isEmpty(content) || !content.contains("access_token")) {
                log.info(content);
                throw new CommonException("获取公众号accessToken失败");
            }
            token = JSONObject.parseObject(content).getString("access_token");
            // 设置为1.9h(有效期2h)
            wx_token_map.put("token", token);
            wx_token_map.put("time", System.currentTimeMillis());
        } else {
            Long time = wx_token_map.getLong("time");
            long l = System.currentTimeMillis();
            if ((l - time) >= 1.9 * 3600 * 1000) {
                wx_token_map.clear();
                getAccessToken(sAppid, sSecret);
            }

        }
        return token;
    }

    public String weiXinSend(Map<String, Object> param) {
        String newParam = transferParam(param);
        return sendGet("https://api.weixin.qq.com/sns/jscode2session", newParam);
    }

    public String transferParam(Map<String, Object> param) {
        if (param.size() < 0) {
            return null;
        }
        String resultPam = "appid=" + commonProperties.getProgramAppId() + "&secret=" + commonProperties.getProgramSecret() + "&grant_type=" + "authorization_code";
        System.out.println(resultPam);
        for (Map.Entry<String, Object> vo : param.entrySet()) {
            resultPam += "&" + vo.getKey() + "=" + vo.getValue();
        }
        return resultPam;
    }


    public String sendGet(String url, String param) {
        log.info("======绑定微信接口url:" + url + "=======");
        log.info("======绑定微信接口入参:" + param + "=======");
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            log.info("=======绑定微信接口地址:" + urlNameString + "========");
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null)
                    in.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }


    /**
     * @param
     * @param
     * @return
     */
    public void sendProjectExpireMsg(OaWxSendLog wxSendLog, WxUserMsgParam wxUserMsgParam) {
        WechatTemplateMsg wechatTemplateMsg = new WechatTemplateMsg();
        wechatTemplateMsg.setTemplate_id(wxUserMsgParam.getTemplateId());
        wechatTemplateMsg.setTouser(wxUserMsgParam.getOpenId());
        HashMap<String, String> miniprogram = new HashMap<>();
        miniprogram.put("appid", commonProperties.getProgramAppId());
        //miniprogram.put("pagepath", "pages/appointment/list");
        wechatTemplateMsg.setMiniprogram(miniprogram);

        TreeMap<String, TreeMap<String, String>> params = new TreeMap<>();
        //根据具体模板参数组装
        if(ObjectUtil.isNotEmpty(wxUserMsgParam.getParam1())){
            params.put(wxUserMsgParam.getParam1(), WechatTemplateMsg.item(wxUserMsgParam.getParamData1()));
        }
        if(ObjectUtil.isNotEmpty(wxUserMsgParam.getParam2())){
            params.put(wxUserMsgParam.getParam2(), WechatTemplateMsg.item(wxUserMsgParam.getParamData2()));
        }
        if(ObjectUtil.isNotEmpty(wxUserMsgParam.getParam3())){
            params.put(wxUserMsgParam.getParam3(), WechatTemplateMsg.item(wxUserMsgParam.getParamData3()));
        }
        wechatTemplateMsg.setData(params);
        log.info("==========公众号appId:"+commonProperties.getOfficialAppId()+"==========");
        wechatTemplateMsg.setAppidReq(commonProperties.getOfficialAppId());
        log.info("==========公众号密钥:"+commonProperties.getOfficialSecret()+"==========");
        wechatTemplateMsg.setSecretReq(commonProperties.getOfficialSecret());

        log.info(JSONObject.toJSONString(wechatTemplateMsg));

        StringBuffer url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=");
        try {
            url.append(URLEncoder.encode(getAccessToken(
                    wechatTemplateMsg.getAppidReq(), wechatTemplateMsg.getSecretReq()), "UTF-8"));
            log.info("==========公众号发送通知url:"+url+"==========");
            String result = HttpClientUtil.doPostJson(url.toString(), JSONObject.toJSONString(wechatTemplateMsg));
            log.info("==========send WxMsg :{}", JSONObject.toJSONString(result));
            if (ObjectUtil.isNotNull(wxSendLog)) {
                wxSendLog.setSendMsg(JSONObject.toJSONString(wechatTemplateMsg));
                wxSendLog.setBackMsg(JSONObject.toJSONString(result));
                oaWxSendLogService.save(wxSendLog);
            }
        } catch (UnsupportedEncodingException e) {
            log.info("----模板消息发送失败-----");
            e.printStackTrace();
        }
    }
}
