package de.votian.services.security;

import de.votian.services.dto.UserSessionDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class AccessControlServiceTest {

    private AccessControlService accessControlService;
    private de.votian.services.service.ParameterService parameterService;

    @BeforeEach
    void setUp() {
        parameterService = mock(de.votian.services.service.ParameterService.class);
        accessControlService = new AccessControlService(null, parameterService);
    }

    @Test
    void canExportJobsForHeadquartersUsesLegacyRight42() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(50, 4, 42));

        assertThat(accessControlService.canViewJobs(user)).isTrue();
        assertThat(accessControlService.canExportJobs(user)).isTrue();

        user.setLegacyRights(rights(50, 4));

        assertThat(accessControlService.canViewJobs(user)).isTrue();
        assertThat(accessControlService.canExportJobs(user)).isFalse();
    }

    @Test
    void canExportJobsForCustomerRequiresExportBit() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(2);
        user.setLegacyRights(rights(16, 4, 7));

        assertThat(accessControlService.canViewJobs(user)).isTrue();
        assertThat(accessControlService.canExportJobs(user)).isTrue();

        user.setLegacyRights(rights(16, 4));

        assertThat(accessControlService.canViewJobs(user)).isTrue();
        assertThat(accessControlService.canExportJobs(user)).isFalse();
    }

    @Test
    void canUseLonghaulRemoteDbRequiresConfiguredEmployeeId() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setEmployeeId(23L);
        user.setLegacyRights(rights(16, 10));

        when(parameterService.getParameterValueWithFallback("LONGHAUL_REMOTE_DB_EMPLOYEE_IDS", 0L))
                .thenReturn(",5,23,42,");

        assertThat(accessControlService.canUseLonghaulRemoteDb(user)).isTrue();

        user.setEmployeeId(99L);

        assertThat(accessControlService.canUseLonghaulRemoteDb(user)).isFalse();
    }

    @Test
    void canViewTrackingForCustomerRequiresEnabledTrackingParameter() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(2);
        user.setHeadquartersId(1L);
        user.setEmployeeId(12L);
        user.setCustomerId(44L);
        user.setLegacyRights(rights(16, 4));

        when(parameterService.getParameterValueFullFallback(12L, "TRACKING_ENABLED_CS_44", 1L)).thenReturn("1");

        assertThat(accessControlService.canViewTracking(user)).isTrue();

        when(parameterService.getParameterValueFullFallback(12L, "TRACKING_ENABLED_CS_44", 1L)).thenReturn("");
        when(parameterService.getParameterValueFullFallback(12L, "CS_TRACKING_ENABLED", 1L)).thenReturn("");

        assertThat(accessControlService.canViewTracking(user)).isFalse();
    }

    @Test
    void canViewTrackingForHeadquartersUsesDispositionOrJobRights() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(25, 19));

        assertThat(accessControlService.canViewTracking(user)).isTrue();

        user.setLegacyRights(rights(25));

        assertThat(accessControlService.canViewTracking(user)).isFalse();
    }

    @Test
    void canManageImportsUsesLegacyImportAndTransferRights() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(30, 22));

        assertThat(accessControlService.canManageImports(user)).isTrue();

        user.setLegacyRights(rights(30, 23));
        assertThat(accessControlService.canManageImports(user)).isTrue();

        user.setLegacyRights(rights(30, 15));
        assertThat(accessControlService.canManageImports(user)).isTrue();

        user.setLegacyRights(rights(30));
        assertThat(accessControlService.canManageImports(user)).isFalse();
    }

    @Test
    void canViewGroupwareUsesLegacyRight11() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(20, 11));

        assertThat(accessControlService.canViewGroupware(user)).isTrue();
        assertThat(accessControlService.canManageGroupware(user)).isTrue();

        user.setLegacyRights(rights(20));

        assertThat(accessControlService.canViewGroupware(user)).isFalse();
        assertThat(accessControlService.canManageGroupware(user)).isFalse();
    }

    @Test
    void canViewGenericExportsUsesLegacyBitsForHeadquartersAndCustomer() {
        UserSessionDto headquarterUser = new UserSessionDto();
        headquarterUser.setUserType(1);
        headquarterUser.setLegacyRights(rights(20, 6));

        assertThat(accessControlService.canViewGenericExports(headquarterUser)).isTrue();

        headquarterUser.setLegacyRights(rights(20));
        assertThat(accessControlService.canViewGenericExports(headquarterUser)).isFalse();

        UserSessionDto customerUser = new UserSessionDto();
        customerUser.setUserType(2);
        customerUser.setLegacyRights(rights(20, 7));

        assertThat(accessControlService.canViewGenericExports(customerUser)).isTrue();

        customerUser.setLegacyRights(rights(20));
        assertThat(accessControlService.canViewGenericExports(customerUser)).isFalse();
    }

    @Test
    void canViewReportsUsesLegacyRight16AndDomainRights() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(25, 0, 16));

        assertThat(accessControlService.canViewCustomerReports(user)).isTrue();
        assertThat(accessControlService.canViewReports(user)).isTrue();

        user.setLegacyRights(rights(25, 1, 16));
        assertThat(accessControlService.canViewCourierReports(user)).isTrue();
        assertThat(accessControlService.canViewReports(user)).isTrue();

        user.setLegacyRights(rights(25, 16));
        assertThat(accessControlService.canViewReports(user)).isFalse();
    }

    @Test
    void canManageMetaFieldsUsesHeadquartersAdminRight() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(10, 2));

        assertThat(accessControlService.canManageMetaFields(user)).isTrue();

        user.setLegacyRights(rights(10));
        assertThat(accessControlService.canManageMetaFields(user)).isFalse();
    }

    @Test
    void canViewConfidentialReportsUsesLegacyRight10() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(20, 10));

        assertThat(accessControlService.canViewConfidentialReports(user)).isTrue();

        user.setLegacyRights(rights(20));
        assertThat(accessControlService.canViewConfidentialReports(user)).isFalse();
    }

    @Test
    void canViewCommunicationCombinesTickerMessageAndGroupRights() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(25, 4));

        assertThat(accessControlService.canManageDeviceMessages(user)).isTrue();
        assertThat(accessControlService.canViewCommunication(user)).isTrue();

        user.setLegacyRights(rights(25, 18));
        assertThat(accessControlService.canManageTicker(user)).isTrue();
        assertThat(accessControlService.canViewCommunication(user)).isTrue();

        user.setLegacyRights(rights(25, 1));
        assertThat(accessControlService.canManageCourierMessageGroups(user)).isTrue();
        assertThat(accessControlService.canViewCommunication(user)).isTrue();

        user.setLegacyRights(rights(25));
        assertThat(accessControlService.canViewCommunication(user)).isFalse();
    }

    @Test
    void canViewGeoOperationsCombinesMapSearchAndAddressRights() {
        UserSessionDto user = new UserSessionDto();
        user.setUserType(1);
        user.setLegacyRights(rights(25, 19));

        assertThat(accessControlService.canViewGlobalMap(user)).isTrue();
        assertThat(accessControlService.canViewGeoOperations(user)).isTrue();

        user.setLegacyRights(rights(25, 2));
        assertThat(accessControlService.canManageAddressDirectory(user)).isTrue();
        assertThat(accessControlService.canManageTravelTimes(user)).isTrue();
        assertThat(accessControlService.canViewGeoOperations(user)).isTrue();

        user.setLegacyRights(rights(25, 0));
        assertThat(accessControlService.canViewSimilaritySearch(user)).isTrue();
        assertThat(accessControlService.canViewGeoOperations(user)).isTrue();

        user.setLegacyRights(rights(25));
        assertThat(accessControlService.canViewGeoOperations(user)).isFalse();
    }

    private String rights(int length, int... enabledBits) {
        char[] flags = "0".repeat(length).toCharArray();
        for (int bit : enabledBits) {
            flags[bit] = '1';
        }
        return new String(flags);
    }
}
