package com.yida.data.common.core.utils;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.constant.QywxConstant;
import com.yida.data.common.core.entity.constant.WxPublicConstant;
import com.yida.data.common.core.entity.notice.qywx.BaseSchoolNotice;
import com.yida.data.common.core.entity.notice.qywx.BaseStaffNotice;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.user.*;
import com.yida.data.common.core.exception.FebsException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class WxUtil {

    /**
     * 企业微信返回码
     */
    public static final String ERR_CODE = "errcode";

    /**
     * 企业微信对返回码的文本描述内容
     */
    public static final String ERR_MESSAGE = "errmsg";

    /**
     * 企业微信接口成功状态码
     */
    public static final String SUCCESS_CODE = "0";

    @Autowired
    private RedisService redisService;

    private static String post(String url, String body) {
        return post(1, url, body);
    }

    private static String post(String url, Map body) {
        return post(1, url, body);
    }

    private static String post(Integer count, String url, String body) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.post(url, body);
            } catch (Exception e) {
                log.error("调用企业微信接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = post(++count, url, body);
                }
            }
            return res;
        }
        return null;
    }

    private static String post(Integer count, String url, Map body) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.post(url, body);
            } catch (Exception e) {
                log.error("调用企业微信接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = post(++count, url, body);
                }
            }
            return res;
        }
        return null;
    }

    private static String get(String url, Map params) {
        return get(1, url, params);
    }

    private static String get(Integer count, String url, Map params) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.get(url, params);
            } catch (Exception e) {
                log.error("调用企业微信接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = get(++count, url, params);
                }
            }
            return res;
        } else {
            return null;
        }
    }

    public String getAccessToken(String corpId, String secret) {
        String accessToken = String.valueOf(redisService.get(FebsConstant.QYWX_ACCESS_TOKEN + corpId + "." + secret));
        if ("null".equals(accessToken)) {
            Map<String, Object> params = new HashMap<>();
            params.put("corpid", corpId);
            params.put("corpsecret", secret);
            // 请求微信access token
            String response = get(QywxConstant.GET_TOKEN_URL,
                params);
            JSONObject token = JSONUtil.parseObj(response);
            if (!"0".equals(token.containsKey("errcode") ? token.get("errcode").toString() : null)) {
                log.error("请微信求access token失败，code:{},msg:{}", token.get("errcode"),
                    token.get("errmsg"));
                throw new FebsException("验证失败");
            }
            accessToken = token.get("access_token").toString();
            // 缓存accessToken两小时
            redisService.set(FebsConstant.QYWX_ACCESS_TOKEN + corpId + "." + secret, accessToken, 7200L);
        }
        return accessToken;
    }

    /**
     * 微信公众平台获取openId
     *
     * @return
     */
    public String getOpenId(String appId, String secret, String code) {
        Map<String, Object> params = new HashMap<>();
        params.put("appId", appId);
        params.put("secret", secret);
        params.put("code", code);
        params.put("grant_type", "authorization_code");
        // 请求微信access token
        String response = get(QywxConstant.GET_PUBLIC_TOKEN_URL, params);
        JSONObject token = JSONUtil.parseObj(response);
        if (token.containsKey("errcode") && !"0".equals(token.get("errcode"))) {
            log.error("请微信求access token失败，code:{},msg:{}", token.get("errcode"),
                token.get("errmsg"));
            throw new FebsException("验证失败");
        }
        return token.getStr("openid");
    }

    public Boolean pushSchoolNotice(String token, BaseSchoolNotice notice) {
        JSONObject resp = JSONUtil.parseObj(post(QywxConstant.PUSH_SCHOOL_NOTICE_URL + token,
            JSONUtil.toJsonStr(notice).replace("\\n", "\n")));
//        log.info("打印学校消息推送信息: {}", JSONUtil.toJsonStr(notice).replace("\\n", "\n"));
        if (!"0".equals(resp.containsKey("errcode") ? resp.get("errcode").toString() : null)) {
            log.error("微信通知发送失败,msg:{},notice:{}", resp, notice);
            return false;
        }
        return true;
    }


    public Boolean pushStaffNotice(String token, BaseStaffNotice notice) {
//        log.info("打印学校消息推送信息: {}", JSONUtil.toJsonStr(notice).replace("\\n", "\n"));
        JSONObject resp = JSONUtil.parseObj(post(QywxConstant.PUSH_STAFF_NOTICE_URL + token,
            JSONUtil.toJsonStr(notice).replace("\\n", "\n")));
//        log.info("打印学校消息推送信息返回信息: {}", resp);
        if (!"0".equals(resp.containsKey("errcode") ? resp.get("errcode").toString() : null)) {
            log.error("微信通知发送失败,msg:{},notice:{}", resp.get("errmsg"), JSONUtil.toJsonStr(notice).replace("\\n", "\n"));
            return false;
        }
        return true;
    }

    public String uploadTempFile(String token, String type, File file) {
        //type 图片（image）、语音（voice）、视频（video），普通文件（file）
        String url = QywxConstant.UPLOAD_TEMP_FILEE_URL + "?access_token=" + token + "&type=" + type;
        Map<String, Object> body = new HashMap<>();
        body.put("file", file);
        JSONObject resp = JSONUtil.parseObj(post(url, body));
        if (!"0".equals(resp.containsKey("errcode") ? resp.get("errcode").toString() : null)) {
            return null;
        }
        return resp.get("media_id").toString();
    }

    /**
     * 获取企业通讯录的成员列表
     */
    public JSONArray getUserList(String accessToken, Long deptId) {
        // 查询用户微信userid
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("department_id", deptId);
        params.put("fetch_child", 1);
        String response = get(QywxConstant.USER_DETAIL_LIST_URL, params);
        JSONObject user = JSONUtil.parseObj(response);
        if (!"0".equals(user.containsKey("errcode") ? user.get("errcode").toString() : null)) {
            log.error("微信获取部门用户信息失败，code:{},msg:{}", user.get("errcode"),
                user.get("errmsg"));
            throw new FebsException("微信获取部门用户信息失败");
        }
        return user.getJSONArray("userlist");
    }

    /**
     * 获取成员ID列表
     *
     * @param accessToken 调用接口凭证
     * @param cursor      用于分页查询的游标，字符串类型，由上一次调用返回，首次调用不填
     * @param limit       分页，预期请求的数据量，取值范围 1 ~ 10000
     * @return cn.hutool.json.JSONArray
     * @author ZYJ
     * @date 2022/12/6 17:35
     */
    public JSONArray getUserIdList(String accessToken, String cursor, String limit, JSONArray jsonArray) {
        // 封装请求参数
        JSONObject params = JSONUtil.createObj()
            .set("limit", limit);
        if (StrUtil.isNotBlank(cursor)) {
            params.set("cursor", cursor);
        }
        String response = post(QywxConstant.USER_ID_LIST_URL + accessToken, params.toString());
        JSONObject jsonObject = JSONUtil.parseObj(response);
        log.info("企业微信获取成员ID列表请求参数: {}, 返回值: {}", params, jsonObject);
        if (!SUCCESS_CODE.equals(jsonObject.containsKey(ERR_CODE) ? jsonObject.get(ERR_CODE).toString() : null)) {
            log.error("企业微信获取获取成员ID列表失败，code:{},msg:{}", jsonObject.get(ERR_CODE), jsonObject.get(ERR_MESSAGE));
            throw new FebsException("企业微信获取获取成员ID列表失败");
        }
        // 获取成员列表id数据
        JSONArray deptUser = jsonObject.getJSONArray("dept_user");
        jsonArray.addAll(deptUser);
        // 获取分页游标
        String nextCursor = jsonObject.getStr("next_cursor");
        if (StrUtil.isNotBlank(nextCursor)) {
            getUserIdList(accessToken, nextCursor, limit, jsonArray);
        }
        return jsonArray;
    }

    /**
     * 使用授权登陆code，获取成员信息，通讯录成员返回UserId，家长返回parent_userid
     */
    public JSONObject getUserInfo(String accessToken, String code) {
        // 查询用户微信userid
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("code", code);
        String response = get(QywxConstant.USER_INFO_URL, params);
        JSONObject user = JSONUtil.parseObj(response);
        if (!SUCCESS_CODE.equals(user.containsKey(ERR_CODE) ? user.get(ERR_CODE).toString() : null)) {
            log.error("请求微信用户信息失败，code:{},msg:{}", user.get(ERR_CODE),
                user.get(ERR_MESSAGE));
            throw new FebsException("获取用户信息失败");
        }
        return user;
    }

    /**
     * 查询用户详细信息
     */
    public JSONObject getUserDetail(String accessToken, String userId) {
        // 查询用户微信userid
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("userid", userId);
        String userDetailResponse = get(QywxConstant.USER_DETAIL_URL, params);
        JSONObject userDetail = JSONUtil.parseObj(userDetailResponse);
        log.info("请求企业微信用户详细信息请求参数: {}, 返回值: {}", params, userDetail);
        if (!SUCCESS_CODE.equals(userDetail.containsKey(ERR_CODE) ? userDetail.get(ERR_CODE).toString() : null)) {
            log.error("请求企业微信用户详细信息失败，code:{},msg:{}", userDetail.get(ERR_CODE),
                userDetail.get(ERR_MESSAGE));
            throw new FebsException("请求企业微信用户详细信息失败");
        }
        return userDetail;
    }

    /**
     * 查询用户敏感信息
     *
     * @param accessToken 调用接口凭证
     * @param userTicket  成员票据
     * @return cn.hutool.json.JSONObject
     * @author ZYJ
     * @date 2022/11/28 15:35
     */
    public JSONObject getUserSensitiveInfo(String accessToken, String userTicket) {
        JSONObject params = JSONUtil.createObj()
            .set("user_ticket", userTicket);
        String userDetailResponse = post(QywxConstant.USER_SENSITIVE_INFO_URL + accessToken, params.toString());
        JSONObject userDetail = JSONUtil.parseObj(userDetailResponse);
        log.info("查询用户敏感信息请求参数: {}, 返回值: {}", params, userDetail);
        if (!SUCCESS_CODE.equals(userDetail.containsKey(ERR_CODE) ? userDetail.get(ERR_CODE).toString() : null)) {
            log.error("查询用户敏感信息失败，code:{}, msg:{}", userDetail.get(ERR_CODE),
                userDetail.get(ERR_MESSAGE));
            throw new FebsException("查询用户敏感信息失败");
        }
        return userDetail;
    }

    /**
     * 创建企业微信部门
     */
    public Long createDept(String accessToken, Dept dept) {
        Map<String, Object> body = new HashMap<>();
        body.put("name", dept.getDeptName());
        body.put("parentid", dept.getParentWxId());
        if (dept.getOrderNum() != null) {
            body.put("order", dept.getOrderNum());
        }
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.DEPT_CREATE_URL + "?access_token=" + accessToken, JSONUtil.toJsonPrettyStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信创建部门失败，code:{},msg:{},dept:{}", response.get("errcode"),
                response.get("errmsg"), dept);
            throw new FebsException("创建部门失败");
        }
        return Long.valueOf(response.get("id").toString());
    }

    /**
     * 更新企业微信部门
     */
    public void updateDept(String accessToken, Dept dept) {
        Map<String, Object> body = new HashMap<>();
        body.put("name", dept.getDeptName());

        if (Objects.nonNull(dept.getParentWxId())) {
            body.put("parentid", dept.getParentWxId());
        }
        body.put("id", dept.getWxId());
        if (dept.getOrderNum() != null) {
            body.put("order", dept.getOrderNum());
        }
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.DEPT_UPDATE_URL + "?access_token=" + accessToken, JSONUtil.toJsonPrettyStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信更新部门失败，code:{},msg:{},dept:{}", response.get("errcode"),
                response.get("errmsg"), dept);
            throw new FebsException("更新部门失败");
        }
    }

    /**
     * 删除企业微信部门
     */
    public void deleteDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("id", deptId);

        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.DEPT_DELETE_URL, params));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信删除部门失败，code:{},msg:{},params:{}", response.get("errcode"),
                response.get("errmsg"), params);
            throw new FebsException("删除部门失败，请检查是否包含成员或子部门");
        }
    }

    /**
     * 获取部门列表
     */
    public List<Map> listDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        if (deptId != null) {
            params.put("id", deptId);
        }
        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.DEPT_LIST_URL, params));
        log.info("获取企业微信部门列表请求参数: {}, 返回值: {}", params, response);
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("获取企业微信部门列表失败，code:{},msg:{},params:{}", response.get("errcode"),
                response.get("errmsg"), params);
            throw new FebsException("获取企业微信部门列表失败");
        }

        return response.getJSONArray("department").toList(Map.class);
    }

    /**
     * 获取子部门ID列表
     *
     * @param accessToken 调用接口凭证
     * @param deptId      部门id。获取指定部门及其下的子部门（以及子部门的子部门等等，递归）。 如果不填，默认获取全量组织架构
     * @return java.util.List<java.util.Map>
     * @author ZYJ
     * @date 2023/4/24 10:46
     */
    public List<Map> listSimpleDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        if (deptId != null) {
            params.put("id", deptId);
        }
        JSONObject response = JSONUtil.parseObj(get(QywxConstant.SIMPLE_DEPT_LIST_URL, params));
        log.info("获取企业微信子部门ID列表请求参数: {}, 返回值: {}", params, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("获取企业微信子部门ID列表失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), params);
            throw new FebsException("获取企业微信子部门ID列表失败");
        }
        return response.getJSONArray("department_id").toList(Map.class);
    }

    /**
     * 获取单个部门详情
     */
    public JSONObject getDeptInfo(String accessToken, String deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        if (deptId != null) {
            params.put("id", deptId);
        }
        JSONObject response = JSONUtil.parseObj(get(QywxConstant.DEPT_INFO_URL, params));
        log.info("获取企业单个部门详情请求参数: {}, 返回值: {}", params, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("获取企业单个部门详情失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), params);
            throw new FebsException("获取企业单个部门详情失败");
        }
        return response.getJSONObject("department");
    }

    /**
     * 创建企业微信部门（家校沟通）
     */
    @Deprecated
    public Long createSchoolDept(String accessToken, Dept dept) {
        Map<String, Object> body = new HashMap<>();
        body.put("name", dept.getDeptName());
        body.put("parentid", dept.getParentWxId());
        body.put("type", dept.getDeptType());

        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_CREATE_URL + "?access_token=" + accessToken, body));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信创建部门(家校)失败，code:{},msg:{},dept:{}", response.get("errcode"),
                response.get("errmsg"), dept.toString());
            throw new FebsException("创建部门失败(家校)");
        }
        return Long.valueOf(response.get("id").toString());
    }

    /**
     * 更新企业微信部门（家校沟通）
     */
    @Deprecated
    public void updateSchoolDept(String accessToken, Dept dept, EduTeacherDept teacherDept) {
        Map<String, Object> body = new HashMap<>();
        if (dept != null) {
            body.put("name", dept.getDeptName());
            body.put("id", dept.getDeptId());
            //body.put("standard_grade", dept.getStandGrade());
            //body.put("register_year", dept.getGradeYear());
        } else {
            body.put("id", teacherDept.getDeptWxId());
            body.put("department_admins", Arrays.asList(new HashMap<String, Object>() {{
                put("op", 0);
                put("userid", teacherDept.getTeacherWxId());
                put("type", teacherDept.getType());
                if (StrUtil.isNotBlank(teacherDept.getCourseName())) {
                    put("subject", teacherDept.getCourseName());
                }
            }}));
        }

        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信更新部门(家校)失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("更新部门(家校)失败");
        }
    }

    /**
     * 删除部门管理员（家校沟通）
     */
    public void deleteSchoolDeptUser(String accessToken, EduTeacherDept eduTeacherDept) {
        Map<String, Object> body = new HashMap<>();
        body.put("id", eduTeacherDept.getDeptWxId());
        body.put("department_admins", Arrays.asList(new HashMap<String, Object>() {{
            put("op", 1);
            put("type", eduTeacherDept.getType());
            put("userid", eduTeacherDept.getTeacherWxId());
        }}));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        log.info("删除部门管理员接口,params:[{}],res:[{}]", body, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("企业微信删除部门(家校)管理员失败，code:{},msg:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE));
            throw new FebsException("删除部门(家校)管理员失败");
        }
    }

    /**
     * 删除企业微信部门（家校沟通）
     */
    @Deprecated
    public void deleteSchoolDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("id", deptId);

        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.SCHOOL_DEPT_DELETE_URL, params));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信删除部门(家校)失败，code:{},msg:{},params:{}", response.get("errcode"),
                response.get("errmsg"), params);
            throw new FebsException("删除部门失败，请检查是否包含成员或子部门");
        }
    }

    /**
     * 获取部门列表(家校沟通)
     */
    public List<Map> listSchoolDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        if (deptId != null) {
            params.put("id", deptId);
        }
        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.SCHOOL_DEPT_LIST_URL, params));
        log.info("获取家校沟通部门列表请求参数: {}, 返回值: {}", params, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("获取企业微信部门(家校)列表失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), params);
            throw new FebsException("获取企业微信部门(家校)列表失败");
        }

        return response.getJSONArray("departments").toList(Map.class);
    }

    /**
     * 新建用户
     */
    public void createUser(String accessToken, EduStaff staff) {
        Map<String, Object> body = new HashMap<>();
        body.put("userid", staff.getWxId());
        body.put("name", staff.getName());
        body.put("mobile", staff.getMobile());
        if (CollUtil.isNotEmpty(staff.getStaffDept())) {
            body.put("department",
                staff.getStaffDept().stream().map(EduStaffDept::getDeptWxId).collect(Collectors.toList()));
            body.put("is_leader_in_dept",
                staff.getStaffDept().stream().map(EduStaffDept::getIsLeader).collect(Collectors.toList()));
            List<Long> mainId =
                staff.getStaffDept().stream().filter(x -> x.getIsMain() != null && x.getIsMain() == 0)
                    .map(EduStaffDept::getDeptWxId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(mainId)) {
                body.put("main_department", mainId.get(0));
            }
        } else {
            body.put("department", Collections.singletonList(1));
        }
        if (StrUtil.isNotBlank(staff.getPosition())) {
            body.put("position", staff.getPosition());
        }
        if (StrUtil.isNotBlank(staff.getSex())
            && (StrUtil.equals("0", staff.getSex()) || StrUtil.equals("1", staff.getSex()))
        ) {
            body.put("gender", StrUtil.equals("0", staff.getSex()) ? 1 : StrUtil.equals("1", staff.getSex()));
        }
        if (StrUtil.isNotBlank(staff.getEmail())) {
            body.put("email", staff.getEmail());
        }
        if (StrUtil.isNotBlank(staff.getLandLine())) {
            body.put("telephone", staff.getLandLine());
        }
        if (StrUtil.isNotBlank(staff.getAddress())) {
            body.put("address", staff.getAddress());
        }
        log.info(JSONUtil.toJsonStr(body));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.USER_CREATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信新增用户失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("新增职工失败");
        }
    }

    /**
     * 新建用户
     */
    public void createUserJson(String accessToken, EduStaff teacher) {
        Map<String, Object> body = new HashMap<>();
        body.put("userid", teacher.getWxId());
        body.put("name", teacher.getName());
        body.put("alias", teacher.getAlias());
        body.put("mobile", teacher.getMobile());
        body.put("department", Arrays.asList(1));
        body.put("position", teacher.getPosition());
        body.put("gender", "0".equals(teacher.getSex()) ? "1" : "1".equals(teacher.getSex()) ? "0" :
            null);
        body.put("email", teacher.getEmail());
        body.put("telephone", teacher.getLandLine());
        body.put("is_leader_in_dept", teacher.getIsLeader());
        body.put("external_position", teacher.getForeignPosition());
        body.put("address", teacher.getAddress());
        log.info(JSONUtil.toJsonStr(body));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.USER_CREATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信新增用户失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("新增职工失败");
        }
    }

    /**
     * 更新用户
     */
    public void updateUser(String accessToken, EduStaff staff) {
        Map<String, Object> body = new HashMap<>();
        body.put("userid", staff.getWxId());
        body.put("name", staff.getName());
        body.put("mobile", staff.getMobile());
        if (CollUtil.isNotEmpty(staff.getStaffDept())) {
            body.put("department",
                staff.getStaffDept().stream().map(x -> x.getDeptWxId()).collect(Collectors.toList()));
            body.put("is_leader_in_dept",
                staff.getStaffDept().stream().map(x -> x.getIsLeader()).collect(Collectors.toList()));
            List<Long> mainId =
                staff.getStaffDept().stream().filter(x -> x.getIsMain() != null && x.getIsMain() == 0)
                    .map(x -> x.getDeptWxId()).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(mainId)) {
                body.put("main_department", mainId.get(0));
            }
        } else {
            body.put("department", Arrays.asList(1));
        }
        if (StrUtil.isNotBlank(staff.getPosition())) {
            body.put("position", staff.getPosition());
        }
        if (StrUtil.isNotBlank(staff.getSex()) && !"2".equals(staff.getSex())) {
            body.put("gender", StrUtil.equals("0", staff.getSex())
                ? 1 : 2);
        }
        if (StrUtil.isNotBlank(staff.getEmail())) {
            body.put("email", staff.getEmail());
        }
        if (StrUtil.isNotBlank(staff.getLandLine())) {
            body.put("telephone", staff.getLandLine());
        }
        if (StrUtil.isNotBlank(staff.getAddress())) {
            body.put("address", staff.getAddress());
        }
        log.info(JSONUtil.toJsonStr(body));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.USER_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信修改用户失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("更新职工失败");
        }
    }

    /**
     * 删除用户
     */
    public void deleteUser(String accessToken, List<String> wxIdList) {
        Map<String, Object> body = new HashMap<>();
        body.put("useridlist", wxIdList);
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.USER_DELETE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        log.info("企业微信删除用户请求参数: {}, 返回值: {}", body, response);
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信删除用户失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("删除职工失败");
        }
    }

    /**
     * 获取家长和学生列表
     */
    public JSONArray getStudentList(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("department_id", deptId);
        params.put("fetch_child", 1);

        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.SCHOOL_DEPT_LIST_USER_URL, params));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("获取企业微信列表失败，code:{},msg:{},params:{}", response.get("errcode"),
                response.get("errmsg"), params);
            throw new FebsException("获取企业微信列表失败");
        }

        return response.getJSONArray("students");
    }

    /**
     * 批量创建学生,每次最多100个
     */
    public void createStudent(String accessToken, List<EduStudent> studentList) {
        Map<String, Object> body = new HashMap<>();
        body.put("students", studentList.stream().map(x -> {
                Map<String, Object> temp = new HashMap<>();
                temp.put("student_userid", x.getWxId());
                temp.put("name", x.getStuName());
                temp.put("department", Arrays.asList(x.getClassWxId()));
                return temp;
            }).collect(Collectors.toList())
        );
        log.info("--------------------");
        log.info("body:{}", body);
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.STUDENT_CREATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        log.info("调用批量创建学生接口返回数据: {}", response.toString());
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信新增学生失败，code:{},msg:{},result_list:{}", response.get("errcode"),
                response.get("errmsg"), response.get("result_list"));
            throw new FebsException("新增学生失败");
        }
    }

    /**
     * 批量删除学生 每次最多100个
     */
    public void deleteStudent(String accessToken, List<String> ids) {
        Map<String, Object> body = new HashMap<>();
        body.put("useridlist", ids);
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.STUDENT_DELETE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        log.info("res:[{}]", response);
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信删除学生失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            throw new FebsException("删除学生失败");
        }
    }

    /**
     * 批量更新学生 每次最多100
     */
    public void updateStudent(String accessToken, List<EduStudent> studentList) {
        Map<String, Object> body = new HashMap<>();
        body.put("students", studentList.stream().map(x -> {
                Map<String, Object> temp = new HashMap<>();
                if (StrUtil.isNotBlank(x.getStuNumber()) && !StrUtil.equals(x.getStuNumber(),
                    x.getWxId())) {
                    temp.put("new_student_userid", x.getStuNumber());
                }
                temp.put("student_userid", x.getWxId());
                temp.put("name", x.getStuName());
                temp.put("department", Arrays.asList(x.getClassWxId()));
                return temp;
            }).collect(Collectors.toList())
        );
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.STUDENT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信更新学生失败，code:{},msg:{},result_list:{}", response.get("errcode"),
                response.get("errmsg"), response.get("result_list"));
            throw new FebsException("更新学生失败");
        }
    }

    /**
     * 获取家长或学生信息
     */
    public JSONObject getStudentOrParent(String accessToken, String wxId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("userid", wxId);
        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.STUDENT_PARENT_INFO, params));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信获取家长或学生信息失败，code:{},msg:{}", response.get("errcode"),
                response.get("errmsg"));
            //throw new FebsException("企业微信获取家长或学生信息失败");
            return null;
        }
        return "1".equals(response.get("user_type").toString())
            ? response.getJSONObject("student")
            : response.getJSONObject("parent");
    }

    /**
     * 批量创建家长
     */
    public void createParent(String accessToken, List<EduParent> parents) {
        Map<String, Object> body = new HashMap<>();
        body.put("parents", parents.stream().map(x -> {
                Map<String, Object> temp = new HashMap<>();
                temp.put("parent_userid", x.getWxId());
                temp.put("mobile", x.getMobile());
                temp.put("to_invite", true);
                temp.put("children", x.getChildren());
                return temp;
            }).collect(Collectors.toList())
        );
        log.info(JSONUtil.toJsonStr(body));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.PARENT_CREATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        log.info("企业微信新增家长,res:[{}],params:[{}]", response, body);
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信新增家长失败，code:{},msg:{},result_list:{}", response.get("errcode"),
                response.get("errmsg"), response.get("result_list"));
            throw new FebsException("新增家长失败");
        }
    }

    /**
     * 批量删除家长 每次最多100个
     */
    public void deleteParent(String accessToken, List<String> ids) {
        Map<String, Object> body = new HashMap<>();
        body.put("useridlist", ids);

        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.PARENT_DELETE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonStr(body)));
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信删除家长失败，code:{},msg:{},result_list:{}", response.get("errcode"),
                response.get("errmsg"), response.get("result_list"));
            throw new FebsException("删除家长失败");
        }
    }

    /**
     * 批量更新家长 每次最多100
     */
    public void updateParent(String accessToken, List<EduParent> parents) {
        Map<String, Object> body = new HashMap<>();
        body.put("parents", parents.stream().map(x -> {
                Map<String, Object> temp = new HashMap<>();
                temp.put("parent_userid", x.getWxId());
                temp.put("mobile", x.getMobile());
                temp.put("children", x.getChildren());
                return temp;
            }).collect(Collectors.toList())
        );
        String s = JSONUtil.toJsonPrettyStr(body);
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.PARENT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        log.info("企业微信更新家长,res:[{}],params:[{}]", response, body);
        if (!"0".equals(response.containsKey("errcode") ? response.get("errcode").toString() : null)) {
            log.error("企业微信更新家长失败，code:{},msg:{},result_list:{}", response.get("errcode"),
                response.get("errmsg"), response.get("result_list"));
            throw new FebsException("更新家长失败");
        }
    }

    /**
     * 创建家校部门
     *
     * @param accessToken 请求token
     * @param dept        家校部门信息
     * @return java.lang.Long
     * @author ZYJ
     * @date 2021/11/17 14:14
     */
    public Long createUserDept(String accessToken, EduUserDept dept) {
        JSONObject body = new JSONObject();
        // 当设置了入学年份和标准年级时，该参数将被忽略
        body.set("name", dept.getDeptName());
        body.set("parentid", dept.getParentWxId());
        body.set("type", dept.getDeptType());
        // 排序
        if (Objects.nonNull(dept.getOrderNum())) {
            body.set("order", dept.getOrderNum());
        }
        // 标准年级值, 仅为年级时生效
        if (Objects.nonNull(dept.getStandardGradeValue())) {
            body.set("standard_grade", dept.getStandardGradeValue());
        }
        // 入学年份, 仅为年级时生效
        if (Objects.nonNull(dept.getRegisterYear())) {
            body.set("register_year", dept.getRegisterYear());
        }

        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_CREATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("企业微信创建家校部门失败，code:{}, msg:{}, dept:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), dept.toString());
            throw new FebsException("创建家校部门失败");
        }
        return Long.valueOf(response.get("id").toString());
    }

    /**
     * 更新家校部门
     *
     * @param accessToken 请求token
     * @param dept        家校部门信息
     * @author ZYJ
     * @date 2021/11/18 10:00
     */
    public void updateUserDept(String accessToken, EduUserDept dept) {
        JSONObject body = new JSONObject();
        body.set("name", dept.getDeptName());
        body.set("id", dept.getWxId());

        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("企业微信更新家校部门失败，code:{}, msg:{}, dept:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), dept.toString());
            throw new FebsException("更新家校部门信息失败");
        }
    }

    /**
     * 更新家校部门教师信息
     *
     * @param accessToken 请求token
     * @param teacherDept 家校部门教师信息
     * @author ZYJ
     * @date 2021/11/18 10:00
     */
    public void updateUserDeptTeacherInfo(String accessToken, EduTeacherDept teacherDept) {
        Map<String, Object> body = new HashMap<>();
        body.put("id", teacherDept.getDeptWxId());
        body.put("department_admins", Arrays.asList(new HashMap<String, Object>() {{
            put("op", 0);
            put("userid", teacherDept.getTeacherWxId());
            put("type", teacherDept.getType());
            if (StrUtil.isNotBlank(teacherDept.getCourseName())) {
                put("subject", teacherDept.getCourseName());
            }
        }}));
        JSONObject response = JSONUtil.parseObj(
            post(QywxConstant.SCHOOL_DEPT_UPDATE_URL + "?access_token=" + accessToken,
                JSONUtil.toJsonPrettyStr(body)));
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("企业微信更新家校部门教师信息失败，code:{},msg:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE));
            throw new FebsException("更新家校部门教师信息失败");
        }
    }

    /**
     * 删除家校部门信息
     *
     * @param accessToken 请求token
     * @param deptId      家校部门id
     * @author ZYJ
     * @date 2021/12/1 16:51
     */
    public void deleteUserDept(String accessToken, Long deptId) {
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("id", deptId);

        JSONObject response = JSONUtil.parseObj(
            get(QywxConstant.SCHOOL_DEPT_DELETE_URL, params));
        String code = response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null;
        // 60003代表企业微信部门不存在
        if (!SUCCESS_CODE.equals(code) && !"60003".equals(code)) {
            log.error("企业微信删除家校部门失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                response.get(ERR_MESSAGE), params);
            throw new FebsException("删除家校部门失败，请检查是否包含成员或子部门");
        }
    }

    /**
     * 获取企业微信JS-SDK jsapi_ticket
     *
     * @param accessToken 应用token
     * @param deptId      部门id
     * @return java.lang.String
     * @author ZYJ
     * @date 2023/6/5 14:50
     */
    public String getJsApiTicket(String accessToken, Long deptId) {
        String jsApiTicket =
            String.valueOf(redisService.get(FebsConstant.QYWX_WX_JS_API_TICKET + deptId));
        if ("null".equals(jsApiTicket)) {

            Map<String, Object> params = new HashMap<>();
            params.put("access_token", accessToken);
            // 获取JS-SDK jsapi_ticket
            String response = get(QywxConstant.GET_JS_API_TICKET_URL, params);
            JSONObject token = JSONUtil.parseObj(response);
            if (token.containsKey("errcode") && !"0".equals(token.get("errcode").toString())) {
                log.error("获取JS-SDK jsapi_ticket失败，code:{},msg:{}", token.get("errcode").toString(),
                    token.get("errmsg").toString());
                throw new FebsException("验证失败");
            }
            jsApiTicket = token.get("ticket").toString();
            // 缓存accessToken两小时
            redisService.set(FebsConstant.QYWX_WX_JS_API_TICKET + deptId, jsApiTicket, 7200L);
        }
        return jsApiTicket;
    }
}
