package io.cameleer.server.app.retention;

import io.cameleer.server.core.runtime.App;
import io.cameleer.server.core.runtime.AppService;
import io.cameleer.server.core.runtime.AppVersion;
import io.cameleer.server.core.runtime.AppVersionRepository;
import io.cameleer.server.core.runtime.Deployment;
import io.cameleer.server.core.runtime.DeploymentRepository;
import io.cameleer.server.core.runtime.Environment;
import io.cameleer.server.core.runtime.EnvironmentService;
import io.cameleer.server.core.storage.ArtifactCoordinates;
import io.cameleer.server.core.storage.ArtifactStore;
import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.util.List;
import java.util.UUID;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

class JarRetentionJobTest {

    @Test
    void cleanupDeletesViaArtifactStore() throws Exception {
        EnvironmentService envSvc = mock(EnvironmentService.class);
        AppService appSvc = mock(AppService.class);
        AppVersionRepository versionRepo = mock(AppVersionRepository.class);
        DeploymentRepository deployRepo = mock(DeploymentRepository.class);
        ArtifactStore store = mock(ArtifactStore.class);

        UUID envId = UUID.randomUUID();
        UUID appId = UUID.randomUUID();
        Instant now = Instant.now();
        Environment env = new Environment(envId, "dev", "Dev", false, true,
                null, 2, "slate", now, 7, 7, 7);
        App app = new App(appId, envId, "demo", "Demo", null, now, now);
        // versions ordered DESC by version
        AppVersion v3 = new AppVersion(UUID.randomUUID(), appId, 3, "ignored", "h", "a.jar", 1L, null, null, null);
        AppVersion v2 = new AppVersion(UUID.randomUUID(), appId, 2, "ignored", "h", "a.jar", 1L, null, null, null);
        AppVersion v1 = new AppVersion(UUID.randomUUID(), appId, 1, "ignored", "h", "a.jar", 1L, null, null, null);

        when(envSvc.listAll()).thenReturn(List.of(env));
        when(appSvc.listByEnvironment(envId)).thenReturn(List.of(app));
        when(versionRepo.findByAppId(appId)).thenReturn(List.of(v3, v2, v1));
        when(deployRepo.findByAppId(appId)).thenReturn(List.of()); // none deployed
        when(appSvc.coordinatesFor(v1)).thenReturn(new ArtifactCoordinates("default", appId, 1));

        JarRetentionJob job = new JarRetentionJob(envSvc, appSvc, versionRepo, deployRepo, store);
        job.cleanupOldVersions();

        verify(store).delete(new ArtifactCoordinates("default", appId, 1));
        verify(versionRepo).delete(v1.id());
        verifyNoMoreInteractions(store);
    }

    @Test
    void skipsCurrentlyDeployedVersion() throws Exception {
        EnvironmentService envSvc = mock(EnvironmentService.class);
        AppService appSvc = mock(AppService.class);
        AppVersionRepository versionRepo = mock(AppVersionRepository.class);
        DeploymentRepository deployRepo = mock(DeploymentRepository.class);
        ArtifactStore store = mock(ArtifactStore.class);

        UUID envId = UUID.randomUUID();
        UUID appId = UUID.randomUUID();
        Instant now = Instant.now();
        Environment env = new Environment(envId, "dev", "Dev", false, true,
                null, 2, "slate", now, 7, 7, 7);
        App app = new App(appId, envId, "demo", "Demo", null, now, now);
        AppVersion v3 = new AppVersion(UUID.randomUUID(), appId, 3, "ignored", "h", "a.jar", 1L, null, null, null);
        AppVersion v2 = new AppVersion(UUID.randomUUID(), appId, 2, "ignored", "h", "a.jar", 1L, null, null, null);
        AppVersion v1 = new AppVersion(UUID.randomUUID(), appId, 1, "ignored", "h", "a.jar", 1L, null, null, null);

        when(envSvc.listAll()).thenReturn(List.of(env));
        when(appSvc.listByEnvironment(envId)).thenReturn(List.of(app));
        when(versionRepo.findByAppId(appId)).thenReturn(List.of(v3, v2, v1));
        // v1 is currently deployed — must NOT be touched even though it's beyond the retention=2 cutoff
        Deployment deployedV1 = mock(Deployment.class);
        when(deployedV1.appVersionId()).thenReturn(v1.id());
        when(deployRepo.findByAppId(appId)).thenReturn(List.of(deployedV1));

        JarRetentionJob job = new JarRetentionJob(envSvc, appSvc, versionRepo, deployRepo, store);
        job.cleanupOldVersions();

        verify(store, never()).delete(any());
        verify(versionRepo, never()).delete(any());
    }
}
