package com.iqser.red.service.peristence.v1.server.integration.tests;

import static org.assertj.core.api.Assertions.assertThat;

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.springframework.beans.factory.annotation.Autowired;

import com.iqser.red.service.peristence.v1.server.integration.client.CustomPermissionClient;
import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.peristence.v1.server.integration.utils.TokenService;
import com.iqser.red.service.persistence.management.v1.processor.acl.RedPermission;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntryV2;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileChangeEntryV2;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionMappingModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.permission.CustomPermissionModel;
import org.junit.jupiter.api.Test;

public class DossierStatsAndGetByIdsTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private CustomPermissionClient customPermissionClient;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserProvider userProvider;

    @Autowired
    private DossierClient dossierClient;

    @Autowired
    private FileClient fileClient;


    @Test
    public void testDossierChangesGetByIdsAndViewPermissions() {

        var start = OffsetDateTime.now();
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
        dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getId());
        IntStream.range(0, 5)
                .forEach(x -> dossierTesterAndProvider.provideTestDossier(dossierTemplate, "test dossier: " + x));
        var allDossiers = dossierClient.getDossiers(true, true);

        var dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet())));
        assertThat(allDossiers).hasSameElementsAs(dossiersByIds.getValue().values());

        // test changes for owner
        var changes = dossierClient.changesSinceV2(new JSONPrimitive<>(start));
        assertThat(changes.getDossierChanges().stream().map(DossierChangeEntryV2::getDossierId)).hasSameElementsAs(allDossiers.stream()
                .map(Dossier::getId)
                .collect(Collectors.toSet()));

        // test changes for owner with new timestamp
        var nextChanges = dossierClient.changesSinceV2(new JSONPrimitive<>(OffsetDateTime.now()));
        assertThat(nextChanges.getDossierChanges()).isEmpty();

        var before = OffsetDateTime.now();
        var testFile = fileTesterAndProvider.testAndProvideFile(allDossiers.iterator().next(), "testFile");
        nextChanges = dossierClient.changesSinceV2(new JSONPrimitive<>(before));
        assertThat(nextChanges.getDossierChanges()).isEmpty();
        assertThat(nextChanges.getFileChanges().stream().map(FileChangeEntryV2::getFileId)).containsExactly(testFile.getId());

        var filesToLoad = new HashMap<String, Set<String>>();
        nextChanges.getFileChanges().forEach(fc -> {
            filesToLoad.put(fc.getDossierId(), Set.of(fc.getFileId()));
        });
        var loadedFiles = fileClient.getFilesByIds(new JSONPrimitive<>(filesToLoad));
        assertThat(loadedFiles.getValue().values().stream().flatMap(Collection::stream).collect(Collectors.toSet())).containsExactly(testFile);

        // test get byId for other user
        tokenService.setUser(userProvider.getAltUserId(), "secret");
        dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet())));
        assertThat(allDossiers).hasSameElementsAs(dossiersByIds.getValue().values());

        // test changes for other user
        var changesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(start));
        assertThat(changesUser2.getDossierChanges().stream().map(DossierChangeEntryV2::getDossierId)).hasSameElementsAs(allDossiers.stream()
                .map(Dossier::getId)
                .collect(Collectors.toSet()));

        // test changes for other user with new timestamp
        var nextChangesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(OffsetDateTime.now()));
        assertThat(nextChangesUser2.getDossierChanges()).isEmpty();

        setPermissionsNobodyExceptOwnerCanView();

        dossiersByIds = dossierClient.getDossiersByIds(new JSONPrimitive<>(allDossiers.stream().map(Dossier::getId).collect(Collectors.toSet())));
        assertThat(dossiersByIds.getValue().values()).isEmpty();

        // no visible changes either after permissions removed
        changesUser2 = dossierClient.changesSinceV2(new JSONPrimitive<>(start));
        assertThat(changesUser2.getDossierChanges()).isEmpty();

    }


    private void setPermissionsNobodyExceptOwnerCanView() {

        CustomPermissionModel targetViewPermission = new CustomPermissionModel(RedPermission.VIEW_OBJECT.getMask(),
                RedPermission.VIEW_OBJECT.getName(),
                RedPermission.VIEW_OBJECT.getSort(),
                false);
        List<CustomPermissionModel> mappedViewPermissions = new ArrayList<>();
        List<CustomPermissionMappingModel> customPermissionMappingModels = new ArrayList<>();
        customPermissionMappingModels.add(new CustomPermissionMappingModel(targetViewPermission, mappedViewPermissions));

        customPermissionClient.saveCustomPermissionMappings("Dossier", customPermissionMappingModels);
        customPermissionClient.syncAllCustomPermissions();
    }

}
