package io.delphiplatform.api.util;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

import io.delphiplatform.api.v3.rdb.entity.spotify.SpotifyPlaylistTrackLifetimePublicId;

import static org.junit.jupiter.api.Assertions.assertTrue;

class JpaUtilsTest {

    class RepositoryStub {

        AtomicInteger counter = new AtomicInteger(0);

        <T> List<T> repositoryStubMethod(Collection<T> ids) {
            counter.incrementAndGet();
            return new ArrayList<>(ids);
        }
    }

    @Test
    void split_bySimpleType_1() {
        List<Long> ids = LongStream.range(0, Short.MAX_VALUE).boxed().collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<Long> result = JpaUtils.splitRepositoryMethodCall(ids, repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 1);
        assertTrue(result.size() == ids.size());
    }

    @Test
    void split_bySimpleType_2() {
        List<Long> ids = LongStream.range(0, Short.MAX_VALUE + 1).boxed().collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<Long> result = JpaUtils.splitRepositoryMethodCall(ids, repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 2);
        assertTrue(result.size() == ids.size());
    }

    @Test
    void split_bySimpleType_3() {
        List<Long> ids = LongStream.range(0, 2 * Short.MAX_VALUE).boxed().collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<Long> result = JpaUtils.splitRepositoryMethodCall(ids, repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 2);
        assertTrue(result.size() == ids.size());
    }

    @Test
    void split_bySimpleType_4() {
        List<Long> ids = LongStream.range(0, 2 * Short.MAX_VALUE + 1).boxed().collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<Long> result = JpaUtils.splitRepositoryMethodCall(ids, repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 3);
        assertTrue(result.size() == ids.size());
    }

    @Test
    void split_byCompositeType_1() {
        List<SpotifyPlaylistTrackLifetimePublicId> ids = LongStream.range(0, Short.MAX_VALUE / 2)
            .mapToObj(ignore -> new SpotifyPlaylistTrackLifetimePublicId()).collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<SpotifyPlaylistTrackLifetimePublicId> result = JpaUtils.splitRepositoryMethodCall(ids,
            repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 1);
        assertTrue(result.size() == ids.size());
    }

    @Test
    void split_byCompositeType_2() {
        List<SpotifyPlaylistTrackLifetimePublicId> ids = LongStream.range(0, 1 + Short.MAX_VALUE / 2)
            .mapToObj(ignore -> new SpotifyPlaylistTrackLifetimePublicId()).collect(Collectors.toList());
        RepositoryStub repositoryStub = new RepositoryStub();
        List<SpotifyPlaylistTrackLifetimePublicId> result = JpaUtils.splitRepositoryMethodCall(ids,
            repositoryStub::repositoryStubMethod, Collectors.toList());
        assertTrue(repositoryStub.counter.get() == 2);
        assertTrue(result.size() == ids.size());
    }
}