package com.malk.benteler.service;

import com.malk.benteler.dto.EiamOrganizationalUnitOption;
import com.malk.server.eiam.EiamConf;
import com.malk.server.eiam.EiamOrganizationalUnit;
import com.malk.server.eiam.EiamOrganizationalUnitPage;
import com.malk.service.eiam.EiamClient_OrganizationalUnit;
import com.malk.service.eiam.EiamService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.scheduling.annotation.Scheduled;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * {@link EiamOrganizationalUnitLocalService} 组织树查询测试。
 */
public class EiamOrganizationalUnitLocalServiceTest {

    private EiamService eiamService;
    private EiamClient_OrganizationalUnit client;
    private EiamOrganizationalUnitLocalService service;

    @Before
    public void setUp() {
        eiamService = mock(EiamService.class);
        client = mock(EiamClient_OrganizationalUnit.class);
        EiamConf conf = new EiamConf();
        conf.setInstanceId("instance_test");
        conf.setApplicationId("app_test");
        service = new EiamOrganizationalUnitLocalService(eiamService, client, conf);
        when(eiamService.getAccessToken()).thenReturn("token_test");
    }

    @Test
    public void searchByName_returnsCurrentAndParentNameWithoutChangingId() {
        when(client.listOrganizationalUnits(anyString(), anyString(), anyString(),
                anyString(), anyInt(), anyInt())).thenAnswer(invocation -> {
            String parentId = invocation.getArgument(3);
            if ("ou_root".equals(parentId)) {
                return page(unit("ou_parent", "Corporate", "ou_root"));
            }
            if ("ou_parent".equals(parentId)) {
                return page(unit("ou_technical", "Technical accounts", "ou_parent"));
            }
            return page();
        });

        List<EiamOrganizationalUnitOption> result = service.searchByName("Technical");

        assertEquals(1, result.size());
        assertEquals("ou_technical", result.get(0).getOrganizationalUnitId());
        assertEquals("Technical accounts (Corporate)",
                result.get(0).getOrganizationalUnitName());
        assertEquals("ou_technical", service.resolveUniqueId("Technical accounts"));
        verify(eiamService, times(1)).getAccessToken();
        verify(client, times(3)).listOrganizationalUnits(anyString(), anyString(),
                anyString(), anyString(), anyInt(), anyInt());
    }

    @Test
    public void resolveUniqueId_supportsRootLevelDepartment() {
        when(client.listOrganizationalUnits(anyString(), anyString(), anyString(),
                anyString(), anyInt(), anyInt())).thenAnswer(invocation -> {
            String parentId = invocation.getArgument(3);
            return "ou_root".equals(parentId)
                    ? page(unit("ou_asia", "Asia", "ou_root")) : page();
        });

        assertEquals("ou_asia", service.resolveUniqueId("Asia"));
    }

    @Test
    public void refreshOrganizationUnitCache_runsHourlyDuringWeekdayBusinessHours()
            throws NoSuchMethodException {
        Method method = EiamOrganizationalUnitLocalService.class
                .getMethod("refreshOrganizationUnitCache");
        Scheduled scheduled = method.getAnnotation(Scheduled.class);

        assertNotNull(scheduled);
        assertEquals("0 0 8-19 * * MON-FRI", scheduled.cron());
        assertEquals("Asia/Shanghai", scheduled.zone());
    }

    private EiamOrganizationalUnit unit(String id, String name, String parentId) {
        EiamOrganizationalUnit unit = new EiamOrganizationalUnit();
        unit.setOrganizationalUnitId(id);
        unit.setOrganizationalUnitName(name);
        unit.setParentId(parentId);
        return unit;
    }

    private EiamOrganizationalUnitPage page(EiamOrganizationalUnit... units) {
        EiamOrganizationalUnitPage page = new EiamOrganizationalUnitPage();
        page.setData(units.length == 0
                ? Collections.emptyList() : Collections.singletonList(units[0]));
        page.setTotalCount(units.length);
        return page;
    }
}
