package com.malk.service.dingtalk.impl;

import com.malk.server.common.McException;
import org.junit.Test;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * 钉钉角色原子接口测试。
 */
public class DDImplClient_RoleTest {

    @Test
    public void roleCreate_usesTopApiEndpointAndReturnsRoleId() {
        StubRoleClient client = new StubRoleClient();
        client.enqueue("{\"errcode\":0,\"result\":{\"roleId\":123}}");

        String roleId = client.roleCreate("token", "测试角色", "456");

        assertEquals("123", roleId);
        assertEquals("https://oapi.dingtalk.com/topapi/role/add_role", client.calls.get(0).url);
        assertEquals("456", client.calls.get(0).body.get("groupId"));
    }

    @Test
    public void roleGroupCreate_usesTopApiEndpointAndReturnsGroupId() {
        StubRoleClient client = new StubRoleClient();
        client.enqueue("{\"errcode\":0,\"result\":{\"groupId\":456}}");

        String groupId = client.roleGroupCreate("token", "测试角色组");

        assertEquals("456", groupId);
        assertEquals("https://oapi.dingtalk.com/topapi/role/add_role_group", client.calls.get(0).url);
    }

    @Test
    public void roleAddUsers_moreThanTwenty_splitsRequests() {
        StubRoleClient client = new StubRoleClient();
        List<String> userIds = IntStream.range(0, 21)
                .mapToObj(index -> "user-" + index)
                .collect(Collectors.toList());

        client.roleAddUsers("token", "role-1", userIds);

        assertEquals(2, client.calls.size());
        assertEquals(String.join(",", userIds.subList(0, 20)), client.calls.get(0).body.get("userIds"));
        assertEquals("user-20", client.calls.get(1).body.get("userIds"));
    }

    @Test
    public void getMicroAppVisibleScopes_returnsParsedResponse() {
        StubRoleClient client = new StubRoleClient();
        client.enqueue("{\"errcode\":0,\"deptVisibleScopes\":[1,2],\"userVisibleScopes\":[\"u1\"],\"isHidden\":false}");

        Map response = client.getMicroAppVisibleScopes("token", 100L);

        assertEquals(Arrays.asList(1, 2), response.get("deptVisibleScopes"));
        assertEquals(Collections.singletonList("u1"), response.get("userVisibleScopes"));
    }

    @Test
    public void roleList_passesOptionalParametersAndReturnsResult() {
        StubRoleClient client = new StubRoleClient();
        client.enqueue("{\"errcode\":0,\"result\":{\"hasMore\":false}}");
        Map<String, Object> bodyExt = new HashMap<>();
        bodyExt.put("size", 20L);
        bodyExt.put("offset", 0L);

        Map result = client.roleList("token", bodyExt);

        assertEquals(Boolean.FALSE, result.get("hasMore"));
        assertEquals(bodyExt, client.calls.get(0).body);
    }

    @Test
    public void roleUpdate_vendorError_throwsBusinessException() {
        StubRoleClient client = new StubRoleClient();
        client.enqueue("{\"errcode\":400,\"errmsg\":\"invalid role\"}");

        try {
            client.roleUpdate("token", "role-1", "测试角色");
            fail("钉钉失败响应必须抛出业务异常");
        } catch (McException ex) {
            assertEquals("502", ex.getCode());
        }
    }

    private static class StubRoleClient extends DDImplClient_Role {
        private final List<Call> calls = new ArrayList<>();
        private final Deque<String> responses = new ArrayDeque<>();

        private void enqueue(String response) {
            responses.add(response);
        }

        @Override
        protected String post(String url, Map<String, Object> param, Map body) {
            calls.add(new Call(url, new HashMap<>(body)));
            return responses.isEmpty() ? "{\"errcode\":0}" : responses.removeFirst();
        }
    }

    private static class Call {
        private final String url;
        private final Map body;

        private Call(String url, Map body) {
            this.url = url;
            this.body = body;
        }
    }
}
