import com.correx.core.artifacts.ArtifactState
import com.correx.core.artifacts.DefaultArtifactReducer
import com.correx.core.events.events.ArtifactValidatedEvent
import com.correx.core.events.events.ArtifactValidatingEvent
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.ArtifactLifecyclePhase
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.testing.fixtures.EventFixtures.stored
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class ArtifactReducerTest {

    private lateinit var reducer: DefaultArtifactReducer

    private val artifactId = ArtifactId("art1")
    private val sessionId = SessionId("sess1")
    private val stageId = StageId("stage1")

    @BeforeEach
    fun setup() {
        reducer = DefaultArtifactReducer()
    }

    @Test
    fun `CREATED to VALIDATING is valid`() {
        val state = ArtifactState(phase = ArtifactLifecyclePhase.CREATED)
        val event = stored(payload = ArtifactValidatingEvent(artifactId, sessionId, stageId))
        val result = reducer.reduce(state, event)
        assertTrue(result.isSuccess)
        assertEquals(ArtifactLifecyclePhase.VALIDATING, result.getOrThrow().phase)
    }

    @Test
    fun `VALIDATING to VALIDATED is valid`() {
        val state = ArtifactState(phase = ArtifactLifecyclePhase.VALIDATING)
        val event = stored(payload = ArtifactValidatedEvent(artifactId, sessionId, stageId))
        val result = reducer.reduce(state, event)
        assertTrue(result.isSuccess)
        assertEquals(ArtifactLifecyclePhase.VALIDATED, result.getOrThrow().phase)
    }

    @Test
    fun `CREATED to VALIDATED is invalid`() {
        val state = ArtifactState(phase = ArtifactLifecyclePhase.CREATED)
        val event = stored(payload = ArtifactValidatedEvent(artifactId, sessionId, stageId))
        val result = reducer.reduce(state, event)
        assertTrue(result.isFailure)
        assertTrue(result.exceptionOrNull() is IllegalStateException)
    }

    @Test
    fun `VALIDATED to VALIDATING is invalid`() {
        val state = ArtifactState(phase = ArtifactLifecyclePhase.VALIDATED)
        val event = stored(payload = ArtifactValidatingEvent(artifactId, sessionId, stageId))
        val result = reducer.reduce(state, event)
        assertTrue(result.isFailure)
        assertTrue(result.exceptionOrNull() is IllegalStateException)
    }

    @Test
    fun `ARCHIVED to anything is invalid`() {
        val state = ArtifactState(phase = ArtifactLifecyclePhase.ARCHIVED)
        val event = stored(payload = ArtifactValidatingEvent(artifactId, sessionId, stageId))
        val result = reducer.reduce(state, event)
        assertTrue(result.isFailure)
        assertTrue(result.exceptionOrNull() is IllegalStateException)
    }
}
