package com.correx.testing.contracts.model.orchestration

import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.OrchestrationPausedEvent
import com.correx.core.events.events.OrchestrationResumedEvent
import com.correx.core.events.events.PostFailureDiagnosedEvent
import com.correx.core.events.events.RecoveryProposal
import com.correx.core.events.events.RetryAttemptedEvent
import com.correx.core.events.events.WorkflowCompletedEvent
import com.correx.core.events.events.WorkflowFailedEvent
import com.correx.core.events.events.WorkflowStartedEvent
import com.correx.core.events.serialization.eventJson
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class EventsTest {

    private val workflowId = "workflow-test"

    @Test
    fun `WorkflowStartedEvent survives round-trip`() {
        val event: EventPayload = WorkflowStartedEvent(
            sessionId = SessionId("s1"),
            startStageId = StageId("stage-a"),
            workflowId = workflowId,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `WorkflowCompletedEvent survives round-trip`() {
        val event: EventPayload = WorkflowCompletedEvent(
            sessionId = SessionId("s1"),
            terminalStageId = StageId("stage-a"),
            totalStages = 1,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `PostFailureDiagnosedEvent survives round-trip with a proposal`() {
        // Guards the #294 event AND its nested RecoveryProposal against the silent-registration trap.
        val event: EventPayload = PostFailureDiagnosedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            gate = "execution",
            fingerprint = "fp-abc",
            proposal = RecoveryProposal(
                diagnosis = "type mismatch",
                citedEvidence = "App.tsx: TS2322",
                recoveryAction = "narrow the return type",
                expectedFingerprint = "fp-xyz",
                confidence = 0.9,
                noRecovery = false,
            ),
            decision = "ROUTE",
            routed = true,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `PostFailureDiagnosedEvent survives round-trip with a null proposal`() {
        val event: EventPayload = PostFailureDiagnosedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            gate = "execution",
            fingerprint = "fp-abc",
            proposal = null,
            decision = "TERMINAL_NO_PROPOSAL",
            routed = false,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `WorkflowFailedEvent survives round-trip`() {
        val event: EventPayload = WorkflowFailedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            reason = "Something went wrong",
            retryExhausted = false,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `WorkflowFailedEvent survives round-trip with retry exhausted`() {
        val event: EventPayload = WorkflowFailedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            reason = "Something went wrong",
            retryExhausted = true,
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `OrchestrationPausedEvent survives round-trip`() {
        val event: EventPayload = OrchestrationPausedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            reason = "Requires user approval",
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `OrchestrationResumedEvent survives round-trip`() {
        val event: EventPayload = OrchestrationResumedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `RetryAttemptedEvent survives round-trip`() {
        val event: EventPayload = RetryAttemptedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            attemptNumber = 1,
            maxAttempts = 3,
            failureReason = "Something went wrong",
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }

    @Test
    fun `RetryAttemptedEvent survives round-trip attempt = max attempts`() {
        val event: EventPayload = RetryAttemptedEvent(
            sessionId = SessionId("s1"),
            stageId = StageId("stage-a"),
            attemptNumber = 3,
            maxAttempts = 3,
            failureReason = "Something went wrong",
        )

        val json = eventJson.encodeToString(EventPayload.serializer(), event)
        val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)

        assertEquals(event, decoded)
    }
}
