package zielu.gittoolbox.cache;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static zielu.intellij.test.MockVfsUtil.createDir;

import com.google.common.collect.ImmutableList;
import com.intellij.mock.MockVirtualFile;
import git4idea.repo.GitRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import zielu.gittoolbox.metrics.Metrics;
import zielu.gittoolbox.metrics.MockMetrics;

@Tag("fast")
@ExtendWith({MockitoExtension.class})
@MockitoSettings(strictness = Strictness.WARN)
class VirtualFileRepoCacheImplTest {
  @Mock(stubOnly = true)
  private GitRepository repository;
  @Mock
  private VirtualFileRepoCacheController controller;

  private Metrics mockMetrics = new MockMetrics();

  private MockVirtualFile repositoryRoot = createDir("repoRoot");

  private VirtualFileRepoCacheImpl cache;

  @BeforeEach
  void beforeEach() {
    when(controller.getMetrics()).thenReturn(mockMetrics);
    cache = new VirtualFileRepoCacheImpl(controller);
    cache.initComponent();
    when(repository.getRoot()).thenReturn(repositoryRoot);
  }

  @AfterEach
  void afterEach() {
    cache.disposeComponent();
  }

  @Test
  void getRepoForRootShouldReturnNullIfEmpty() {
    assertThat(cache.getRepoForRoot(createDir("root"))).isNull();
  }

  @Test
  void getRepoForRootShouldReturnRepositoryForRoot() {
    cache.updatedRepoList(ImmutableList.of(repository));
    assertThat(cache.getRepoForRoot(repositoryRoot)).isEqualTo(repository);
  }

  @Test
  void getRepoForDirShouldReturnNullIfEmpty() {
    assertThat(cache.getRepoForDir(createDir("dir"))).isNull();
  }

  @Test
  void getRepoForDirShouldReturnRepositoryForDirInRoot() {
    cache.updatedRepoList(ImmutableList.of(repository));
    MockVirtualFile dirInRoot = createDir(repositoryRoot,"dirInRoot");
    assertThat(cache.getRepoForDir(dirInRoot)).isEqualTo(repository);
  }

  @Test
  void getRepoForDirShouldReturnSameRepositoryForDirInRootIfCalledMoreThanOnce() {
    cache.updatedRepoList(ImmutableList.of(repository));
    MockVirtualFile dirInRoot = createDir(repositoryRoot,"dirInRoot");
    GitRepository repo1 = cache.getRepoForDir(dirInRoot);
    GitRepository repo2 = cache.getRepoForDir(dirInRoot);
    assertThat(repo1).isEqualTo(repo2);
  }

  @Test
  void getRepoForDirShouldReturnRepositoryForDirInDirInRootBottomUp() {
    cache.updatedRepoList(ImmutableList.of(repository));
    MockVirtualFile dirInRoot = createDir(repositoryRoot, "dirInRoot");
    MockVirtualFile dirInDirInRoot = createDir(dirInRoot, "dirInDirInRoot");
    assertThat(cache.getRepoForDir(dirInDirInRoot)).isEqualTo(repository);
  }

  @Test
  void getRepoForDirShouldReturnRepositoryForDirInDirInRootTopDown() {
    cache.updatedRepoList(ImmutableList.of(repository));
    MockVirtualFile dirInRoot = createDir(repositoryRoot, "dirInRoot");
    MockVirtualFile dirInDirInRoot = createDir(dirInRoot, "dirInDirInRoot");
    assertSoftly(softly -> {
      softly.assertThat(cache.getRepoForDir(dirInRoot)).isEqualTo(repository);
      softly.assertThat(cache.getRepoForDir(dirInDirInRoot)).isEqualTo(repository);
    });

  }

  @Test
  void updatedRepoListPublishesToMessageBus() {
    cache.updatedRepoList(ImmutableList.of(repository));
    verify(controller).fireCacheChanged();
  }
}
@@ -695,97 +695,8 @@
 on;%0A
-import org.mockito.junit.jupiter.MockitoSettings;%0Aimport org.mockito.quality.Strictness;%0A
 impo
@@ -732,16 +732,16 @@
 etrics;%0A
+
 import z
@@ -833,55 +833,8 @@
 s%7D)%0A
-@MockitoSettings(strictness = Strictness.WARN)%0A
 clas
@@ -1327,16 +1327,55 @@
 nent();%0A
+  %7D%0A%0A  private void mockRepository() %7B%0A
     when
@@ -1682,32 +1682,55 @@
 toryForRoot() %7B%0A
+    mockRepository();%0A%0A
     cache.update
@@ -2039,24 +2039,47 @@
 rInRoot() %7B%0A
+    mockRepository();%0A%0A
     cache.up
@@ -2356,24 +2356,47 @@
 hanOnce() %7B%0A
+    mockRepository();%0A%0A
     cache.up
@@ -2748,24 +2748,47 @@
 ottomUp() %7B%0A
+    mockRepository();%0A%0A
     cache.up
@@ -3136,24 +3136,47 @@
 TopDown() %7B%0A
+    mockRepository();%0A%0A
     cache.up
@@ -3579,24 +3579,24 @@
  %7D%0A%0A  @Test%0A
-
   void updat
@@ -3627,24 +3627,47 @@
 sageBus() %7B%0A
+    mockRepository();%0A%0A
     cache.up

Create mocks only then needed