package com.malk.service.dingtalk.impl;

import cn.hutool.core.util.ObjectUtil;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.dingtalk.DDClient_Contacts;
import com.malk.utils.UtilDateTime;
import com.malk.utils.UtilList;
import com.malk.utils.UtilMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DDImplClient_Contacts implements DDClient_Contacts {

    /**
     * 获取子部门ID列表 [获取企业部门下的所有直属子部门列表]
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-a-sub-department-id-list-v2
     */
    @Override
    public List<Long> listSubDepartmentId(String access_token, long dept_id) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("dept_id", dept_id);
        Map rsp = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listsubid", null, param, body).getResult();
        List<Number> list = (List<Number>) rsp.get("dept_id_list");
        // ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]
        return list.stream().map(item -> item.longValue()).collect(Collectors.toList());
    }

    /**
     * 获取部门列表
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2
     */
    @Override
    public List<Map> listSubDepartmentDetail(String access_token, long dept_id) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("dept_id", dept_id);
        return (List<Map>) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listsub", null, param, body).getResult();
    }

    /**
     * 获取全部架构内部门_全部 detail [包含一级部门]
     */
    @Override
    public List<Map> getDepartmentDetail_all(String access_token, boolean containsTop) {
        List<Map> deptList = containsTop ? UtilList.asList(getDepartmentInfo(access_token, DDConf.TOP_DEPARTMENT)) : new ArrayList<>();
        return _getDepartment_all(access_token, DDConf.TOP_DEPARTMENT, deptList, false);
    }

    /**
     * 获取全部架构内部门_全部 id [包含一级部门]
     */
    @Override
    public List<Long> getDepartmentId_all(String access_token, boolean containsTop) {
        List<Long> deptList = containsTop ? UtilList.asList(DDConf.TOP_DEPARTMENT) : new ArrayList<>();
        return (List<Long>) _getDepartment_all(access_token, DDConf.TOP_DEPARTMENT, deptList, true)
                .stream().map(detpId -> Long.valueOf(String.valueOf(detpId))).collect(Collectors.toList());
    }

    @Override
    public List<Long> getDepartmentId_all(String access_token, boolean containsTop, long deptId) {
        List<Long> deptList = containsTop ? UtilList.asList(deptId) : new ArrayList<>();
        return (List<Long>) _getDepartment_all(access_token, deptId, deptList, true)
                .stream().map(detpId -> Long.valueOf(String.valueOf(detpId))).collect(Collectors.toList());
    }

    /// 递归查询
    private List _getDepartment_all(String access_token, long deptId, List deptIdList, boolean isIdList) {
        List tList = isIdList ?
                listSubDepartmentId(access_token, deptId) :
                listSubDepartmentDetail(access_token, deptId);
        deptIdList.addAll(tList);
        // 当所有子部门都为空, 递归出口
        for (Object dept : tList) {
            _getDepartment_all(access_token, Long.valueOf(String.valueOf(isIdList ? dept : ((Map) dept).get("dept_id"))), deptIdList, isIdList);
        }
        return deptIdList;
    }

    /**
     * 获取部门用户userid列表 [无需分页]
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/query-the-list-of-department-userids
     */
    @Override
    public List<String> listDepartmentUserId(String access_token, long dept_id) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("dept_id", dept_id);
        Map rsp = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/user/listid", null, param, body).getResult();
        return (List<String>) rsp.get("userid_list");
    }

    /**
     * 查询用户详情
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/query-user-details
     */
    @Override
    public Map getUserInfoById(String access_token, String userId) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("userid", userId);
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/get", null, param, body).getResult();
    }

    /**
     * 查询用户详情
     */
    @Override
    public Map getUserInfoByMobile(String access_token, String mobile) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("mobile", mobile);
        Map result = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/getbymobile", null, param, body).getResult();
        return getUserInfoById(access_token, String.valueOf(result.get("userid")));
    }

    /**
     * 删除用户
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/delete-a-user
     */
    @Override
    public boolean deleteUser(String access_token, String userId) {
        DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/delete", null, DDConf.initTokenParams(access_token), UtilMap.map("userid", userId));
        return true;
    }

    /**
     * 查询离职记录列表
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/query-the-details-of-employees-who-have-left-office
     */
    @Override
    public List<Map<String, String>> getLeaveEmployeeRecords(String access_token, Date startTime, Map extInfo) {
        return _getLeaveEmployeeRecords(access_token, startTime, extInfo, new ArrayList<>());
    }

    /// 递归所有离职人员
    public List<Map<String, String>> _getLeaveEmployeeRecords(String access_token, Date startTime, Map extInfo, List dataList) {
        String start = UtilDateTime.format(startTime, "yyyy-MM-dd'T'HH:mm:ss") + "Z"; // 字符格式
        Map body = UtilMap.map("startTime", start);
        if (ObjectUtil.isNotNull(extInfo)) {
            body.putAll(extInfo);
            if (body.containsKey("endTime")) {
                Date end = (Date) extInfo.get("endTime");
                body.put("endTime", UtilDateTime.format(end, "yyyy-MM-dd'T'HH:mm:ss") + "Z");
            }
        }
        if (!body.containsKey("maxResults")) {
            body.put("maxResults", 50);
        }
        DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com/v1.0/contact/empLeaveRecords", DDConf.initTokenHeader(access_token), body);
        dataList.addAll(ddr_new.getRecords());
        if (StringUtils.isNotBlank(ddr_new.getNextToken())) {
            extInfo = UtilMap.putNotNull(extInfo, "nextToken", ddr_new.getNextToken());
            _getLeaveEmployeeRecords(access_token, startTime, extInfo, dataList);
        }
        return dataList;
    }

    /**
     * 获取指定用户的所有父部门列表
     */
    @Override
    public Map listParentByUser(String access_token, String userId) {
        DDR r = DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listparentbyuser", null, DDConf.initTokenParams(access_token), UtilMap.map("userid", userId));
        return (Map) r.getResult();
    }

    /**
     * 创建用户
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/user-information-creation
     */
    @Override
    public Map createUser(String access_token, String name, String mobile, List<String> dept_id_list, Map body_ext) {
        Map param = UtilMap.map("access_token", access_token);
        String deptIds = String.join(",", dept_id_list.stream().map(dept -> String.valueOf(dept)).collect(Collectors.toList()));
        Map body = UtilMap.map("name, mobile, dept_id_list", name, mobile, deptIds);
        if (ObjectUtil.isNotNull(body_ext)) {
            body.putAll(body_ext);
        }
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/create", null, param, body).getResult();
    }

    /**
     * 创建钉钉自建企业账号
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/create-dingtalk-user-created-dedicated-account
     */
    @Override
    public Map createUser_dingTalk(String access_token, String login_id, String init_password, String name, List<Long> dept_id_list, Map body_ext) {
        Map param = UtilMap.map("access_token", access_token);
        String deptIds = String.join(",", dept_id_list.stream().map(dept -> String.valueOf(dept)).collect(Collectors.toList()));
        Map body = UtilMap.map("exclusive_account, exclusive_account_type, login_id, init_password, name, dept_id_list", true, "dingtalk", login_id, init_password, name, deptIds);
        if (ObjectUtil.isNotNull(body_ext)) {
            body.putAll(body_ext);
        }
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/create", null, param, body).getResult();
    }

    /**
     * 创建部门
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/create-a-department-v2
     */
    @Override
    public Map createDepartment(String access_token, String name, long parent_id, Map body_ext) {

        // 长度限制为1~64个字符，不允许包含字符"-"","以及","
        name = name.replaceAll("-", "").replaceAll(",", "");
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("name, parent_id", name, parent_id);
        if (ObjectUtil.isNotNull(body_ext)) {
            body.putAll(body_ext);
        }
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/create", null, param, body).getResult();
    }

    /**
     * 获取部门详情
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/query-department-details0-v2
     */
    @Override
    public Map getDepartmentInfo(String access_token, long dept_id) {
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/get", null, DDConf.initTokenParams(access_token), UtilMap.map("dept_id", dept_id)).getResult();
    }

    /**
     * 获取员工人数
     */
    @Override
    public int getUserCount(String access_token, boolean only_active) {
        Map result = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/user/count", null, DDConf.initTokenParams(access_token), UtilMap.map("only_active", only_active)).getResult();
        return UtilMap.getInt(result, "count");
    }
}
