package tech.easyflow.agent.runtime.workspace;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import tech.easyflow.agent.config.AgentWorkspaceProperties;
import tech.easyflow.agent.runtime.AgentRunRegistry;
import tech.easyflow.agent.runtime.lock.AgentRunLock;

import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Duration;
import java.time.Instant;

/**
 * {@link AgentWorkspaceCleanupService} 会话锁竞态保护测试。
 */
public class AgentWorkspaceCleanupServiceTest {

    /** 临时工作区。 */
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    /**
     * 验证运行已持有同一会话锁但尚未注册活动态时，清理任务无等待跳过目录。
     *
     * @throws Exception 测试目录准备失败
     */
    @Test
    public void cleanupShouldSkipInitializationWindowWhenSessionLockIsHeld() throws Exception {
        Fixture fixture = fixture();
        Mockito.when(fixture.runRegistry.hasActiveSession("runtime-3")).thenReturn(false);
        Mockito.when(fixture.runLock.tryAcquire(BigInteger.TWO, "runtime-3")).thenReturn(null);

        fixture.service.cleanup();

        Assert.assertTrue(Files.isDirectory(fixture.workspace));
        Mockito.verify(fixture.runLock).tryAcquire(BigInteger.TWO, "runtime-3");
    }

    /**
     * 验证取得清理锁后仍会重检活动态并释放锁，不删除刚完成注册的目录。
     *
     * @throws Exception 测试目录准备失败
     */
    @Test
    public void cleanupShouldRecheckActiveSessionAfterAcquiringLock() throws Exception {
        Fixture fixture = fixture();
        AgentRunLock.Handle handle = Mockito.mock(AgentRunLock.Handle.class);
        Mockito.when(fixture.runRegistry.hasActiveSession("runtime-3")).thenReturn(false, true);
        Mockito.when(fixture.runLock.tryAcquire(BigInteger.TWO, "runtime-3")).thenReturn(handle);

        fixture.service.cleanup();

        Assert.assertTrue(Files.isDirectory(fixture.workspace));
        Mockito.verify(handle).close();
    }

    private Fixture fixture() throws Exception {
        AgentWorkspaceProperties properties = new AgentWorkspaceProperties();
        properties.setRoot(temporaryFolder.newFolder("agent-workspaces").getAbsolutePath());
        properties.setRetention(Duration.ofMinutes(1));
        AgentWorkspaceResolver resolver = new AgentWorkspaceResolver(properties);
        resolver.initialize();
        Path workspace = resolver.resolve(BigInteger.ONE, BigInteger.TWO, "runtime-3");
        Files.setLastModifiedTime(workspace, FileTime.from(Instant.now().minus(Duration.ofHours(2))));
        Files.setLastModifiedTime(
                resolver.activityFile(workspace), FileTime.from(Instant.now().minus(Duration.ofHours(2))));
        AgentRunRegistry runRegistry = Mockito.mock(AgentRunRegistry.class);
        AgentRunLock runLock = Mockito.mock(AgentRunLock.class);
        return new Fixture(workspace, runRegistry, runLock,
                new AgentWorkspaceCleanupService(resolver, properties, runRegistry, runLock));
    }

    private record Fixture(Path workspace,
                           AgentRunRegistry runRegistry,
                           AgentRunLock runLock,
                           AgentWorkspaceCleanupService service) {
    }
}
