package com.correx.core.tasks

import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.RefinementIterationEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.events.TaskClaimedEvent
import com.correx.core.events.events.TaskCreatedEvent
import com.correx.core.events.types.EventId
import com.correx.core.events.types.ProjectId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.TaskId
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class TaskBoardProjectorTest {

    private val projector = TaskBoardProjector(DefaultTaskReducer())
    private val projectId = ProjectId("auth")

    private fun stored(payload: EventPayload, seq: Long) = StoredEvent(
        metadata = EventMetadata(
            eventId = EventId("e-$seq"),
            sessionId = SessionId("tasks:auth"),
            timestamp = Instant.parse("2026-01-01T00:00:0${seq}Z"),
            schemaVersion = 1,
            causationId = null,
            correlationId = null,
        ),
        sequence = seq,
        sessionSequence = seq,
        payload = payload,
    )

    private fun created(id: TaskId) =
        TaskCreatedEvent(id, projectId, id.value, "title ${id.value}", "goal")

    private fun fold(vararg events: StoredEvent): TaskBoard =
        events.fold(projector.initial()) { board, event -> projector.apply(board, event) }

    @Test
    fun `interleaved events update each task independently`() {
        val one = TaskId("auth-1")
        val two = TaskId("auth-2")

        val board = fold(
            stored(created(one), 1),
            stored(created(two), 2),
            stored(TaskClaimedEvent(one, claimant = "claude-opus"), 3),
        )

        assertEquals(2, board.size)
        assertEquals(TaskStatus.IN_PROGRESS, board[one]?.status)
        assertEquals("claude-opus", board[one]?.claimant)
        assertEquals(TaskStatus.TODO, board[two]?.status)
    }

    @Test
    fun `non-task payload leaves the board unchanged`() {
        val one = TaskId("auth-1")
        val withTask = fold(stored(created(one), 1))

        val nonTask = RefinementIterationEvent(
            sessionId = SessionId("s-1"),
            cycleKey = "implement->review",
            iteration = 1,
            maxIterations = 3,
        )
        val after = projector.apply(withTask, stored(nonTask, 2))

        assertEquals(withTask, after)
    }
}
