package com.malk.service.dingtalk.impl;

import com.alibaba.fastjson.JSON;
import com.malk.server.common.McException;
import com.malk.service.dingtalk.DDClient_Role;
import com.malk.utils.UtilHttp;
import com.malk.utils.UtilMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
public class DDImplClient_Role implements DDClient_Role {

    private static final String OAPI = "https://oapi.dingtalk.com";

    /** 钉钉员工角色批量增/删接口单批用户上限(addrolesforemps 文档限 20) */
    private static final int USER_BATCH_SIZE = 20;

    /**
     * 钉钉老接口响应直接平铺(无 result 嵌套):
     * { "errcode":0, "errmsg":"ok", "deptVisibleScopes":[...], "userVisibleScopes":[...], "isHidden":false }
     * 用 UtilHttp 拿原始字符串自解析,绕开 DDR.result 字段限制。
     */
    @Override
    public Map getMicroAppVisibleScopes(String access_token, long agentId) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("agentId", agentId);
        String raw = post(OAPI + "/microapp/visible_scopes", param, body);
        Map rsp = JSON.parseObject(raw, Map.class);
        assertDingSuccess(rsp);
        log.info("[钉钉] 应用可见范围查询成功, agentId={}, 部门数={}, 用户数={}",
                agentId, collectionSize(rsp.get("deptVisibleScopes")), collectionSize(rsp.get("userVisibleScopes")));
        return rsp;
    }

    @Override
    public String roleGroupCreate(String access_token, String name) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("name", name);
        String raw = post(OAPI + "/topapi/role/add_role_group", param, body);
        Map rsp = JSON.parseObject(raw, Map.class);
        assertDingSuccess(rsp);
        Object groupId = rsp.get("groupId");
        if (groupId == null && rsp.get("result") instanceof Map) {
            groupId = ((Map) rsp.get("result")).get("groupId");
        }
        log.info("[钉钉] 创建角色组成功, groupId={}", groupId);
        return groupId == null ? null : String.valueOf(groupId);
    }

    private static void assertDingSuccess(Map rsp) {
        Object errcode = rsp.get("errcode");
        if (errcode != null && !"0".equals(String.valueOf(errcode))) {
            throw new McException("502", "dingtalk errcode=" + errcode + ", errmsg=" + rsp.get("errmsg"));
        }
    }

    @Override
    public String roleCreate(String access_token, String roleName, String groupId) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("roleName, groupId", roleName, groupId);
        String raw = post(OAPI + "/topapi/role/add_role", param, body);
        Map rsp = JSON.parseObject(raw, Map.class);
        assertDingSuccess(rsp);
        Object roleId = rsp.get("roleId");
        if (roleId == null && rsp.get("result") instanceof Map) {
            roleId = ((Map) rsp.get("result")).get("roleId");
        }
        log.info("[钉钉] 创建角色成功, groupId={}, roleId={}", groupId, roleId);
        return roleId == null ? null : String.valueOf(roleId);
    }

    @Override
    public void roleAddUsers(String access_token, String roleId, Collection<String> userIds) {
        callBatch(access_token, OAPI + "/topapi/role/addrolesforemps", roleId, userIds, "add");
    }

    @Override
    public void roleDeleteUsers(String access_token, String roleId, Collection<String> userIds) {
        callBatch(access_token, OAPI + "/topapi/role/removerolesforemps", roleId, userIds, "remove");
    }

    @Override
    public void roleUpdate(String access_token, String roleId, String roleName) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("roleId, roleName", roleId, roleName);
        String raw = post(OAPI + "/topapi/role/update_role", param, body);
        assertDingSuccess(JSON.parseObject(raw, Map.class));
        log.info("[钉钉] 更新角色成功, roleId={}", roleId);
    }

    @Override
    public void roleDelete(String access_token, String roleId) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("role_id", roleId);
        String raw = post(OAPI + "/topapi/role/deleterole", param, body);
        assertDingSuccess(JSON.parseObject(raw, Map.class));
        log.info("[钉钉] 删除角色成功, roleId={}", roleId);
    }

    @Override
    public Map roleList(String access_token, Map body_ext) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = new java.util.HashMap();
        if (body_ext != null) {
            body.putAll(body_ext);
        }
        return resultMap(post(OAPI + "/topapi/role/list", param, body));
    }

    @Override
    public Map roleGet(String access_token, String roleId) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("roleId", roleId);
        return resultMap(post(OAPI + "/topapi/role/getrole", param, body));
    }

    @Override
    public Map roleListEmployees(String access_token, String roleId, long size, long offset) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = UtilMap.map("role_id, size, offset", roleId, size, offset);
        return resultMap(post(OAPI + "/topapi/role/simplelist", param, body));
    }

    @Override
    public void setMicroAppVisibleScopes(String access_token, long agentId,
                                         List<Long> addDeptIds, List<String> addUserIds, List<String> addRoleIds,
                                         List<Long> delDeptIds, List<String> delUserIds, List<String> delRoleIds) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = new java.util.HashMap();
        body.put("agentId", agentId);
        body.put("isHidden", false);
        if (addDeptIds != null && !addDeptIds.isEmpty())
            body.put("addDeptIds", addDeptIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
        if (addUserIds != null && !addUserIds.isEmpty())
            body.put("addUserIds", String.join(",", addUserIds));
        if (addRoleIds != null && !addRoleIds.isEmpty())
            body.put("addRoleIds", String.join(",", addRoleIds));
        if (delDeptIds != null && !delDeptIds.isEmpty())
            body.put("delDeptIds", delDeptIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
        if (delUserIds != null && !delUserIds.isEmpty())
            body.put("delUserIds", String.join(",", delUserIds));
        if (delRoleIds != null && !delRoleIds.isEmpty())
            body.put("delRoleIds", String.join(",", delRoleIds));
        String raw = post(OAPI + "/microapp/set_visible_scopes", param, body);
        assertDingSuccess(JSON.parseObject(raw, Map.class));
        log.info("[钉钉] 设置应用可见范围成功, agentId={}, addDept={}, addUser={}, addRole={}, delDept={}, delUser={}, delRole={}",
                agentId, collectionSize(addDeptIds), collectionSize(addUserIds), collectionSize(addRoleIds),
                collectionSize(delDeptIds), collectionSize(delUserIds), collectionSize(delRoleIds));
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Map> listMicroApp(String access_token) {
        Map param = UtilMap.map("access_token", access_token);
        Map body = new java.util.HashMap();
        String raw = post(OAPI + "/microapp/list", param, body);
        Map rsp = JSON.parseObject(raw, Map.class);
        assertDingSuccess(rsp);
        Object app_list = rsp.get("app_list");
        if (app_list == null) app_list = rsp.get("appList");
        List<Map> apps = app_list instanceof List ? (List<Map>) app_list : new ArrayList<>();
        log.info("[钉钉] 自建应用列表查询成功, 数量={}", apps.size());
        return apps;
    }

    private void callBatch(String access_token, String url, String roleId, Collection<String> userIds, String op) {
        if (userIds == null || userIds.isEmpty()) return;
        List<String> all = new ArrayList<>(userIds);
        Map param = UtilMap.map("access_token", access_token);
        for (int i = 0; i < all.size(); i += USER_BATCH_SIZE) {
            List<String> batch = all.subList(i, Math.min(i + USER_BATCH_SIZE, all.size()));
            String userIdsCsv = batch.stream().collect(Collectors.joining(","));
            Map body = UtilMap.map("roleIds, userIds", roleId, userIdsCsv);
            String raw = post(url, param, body);
            assertDingSuccess(JSON.parseObject(raw, Map.class));
            log.info("[钉钉] 角色成员{}成功, roleId={}, 批次={}/{}, 数量={}",
                    op, roleId, i / USER_BATCH_SIZE + 1,
                    (all.size() + USER_BATCH_SIZE - 1) / USER_BATCH_SIZE, batch.size());
        }
    }

    protected String post(String url, Map<String, Object> param, Map body) {
        return UtilHttp.doPost(url, null, param, body);
    }

    private static Map resultMap(String raw) {
        Map rsp = JSON.parseObject(raw, Map.class);
        assertDingSuccess(rsp);
        return rsp.get("result") instanceof Map ? (Map) rsp.get("result") : rsp;
    }

    private static int collectionSize(Object value) {
        return value instanceof Collection ? ((Collection) value).size() : 0;
    }
}
