package com.correx.core.kernel.orchestration

import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.ExecutionPlanLockedEvent
import com.correx.core.events.events.InitialIntentEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.events.WorkflowCompletedEvent
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.EventId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class PlanPatternMiningTest {

    @Test
    fun `only a session whose executed plan completed is mined`() {
        val events =
            intent("s1", "build a react frontend that compiles") +
                locked("s1", "wf-s1", listOf("scaffold", "impl")) +
                completed("s1", "wf-s1") + // executed plan completed → mined
                intent("s2", "build a react frontend that compiles") +
                locked("s2", "wf-s2", listOf("a", "b")) // no completion → not mined
        val shapes = mineSuccessfulPlanShapes(events, exclude = "current")
        assertEquals(listOf("scaffold", "impl"), shapes.single().stageSequence)
    }

    @Test
    fun `the current session is never mined from itself`() {
        val events = intent("me", "x y z frontend") + locked("me", "wf", listOf("a")) + completed("me", "wf")
        assertTrue(mineSuccessfulPlanShapes(events, exclude = "me").isEmpty())
    }

    @Test
    fun `keyword overlap ignores stopwords and short tokens`() {
        val a = intentKeywords("Build a React frontend that compiles")
        val b = intentKeywords("Create a React frontend with routing")
        assertTrue("react" in a && "frontend" in a)
        assertTrue("the" !in a && "a" !in a)
        assertTrue(keywordOverlap(a, b) > 0.0)
        assertEquals(0.0, keywordOverlap(a, emptySet()))
    }

    private var seq = 0L
    private fun ev(sid: String, payload: EventPayload) = listOf(
        StoredEvent(
            metadata = EventMetadata(
                eventId = EventId("e${seq++}"),
                sessionId = SessionId(sid),
                timestamp = Instant.parse("2026-01-01T00:00:00Z"),
                schemaVersion = 1,
                causationId = null,
                correlationId = null,
            ),
            sequence = seq,
            sessionSequence = seq,
            payload = payload,
        ),
    )

    private fun intent(sid: String, text: String) = ev(sid, InitialIntentEvent(SessionId(sid), text))
    private fun locked(sid: String, wf: String, stages: List<String>) = ev(
        sid,
        ExecutionPlanLockedEvent(SessionId(sid), ArtifactId("execution_plan"), wf, stages, stages.first()),
    )
    private fun completed(sid: String, wf: String) =
        ev(sid, WorkflowCompletedEvent(SessionId(sid), StageId("end"), 2, wf))
}
