package com.correx.core.talkie

import com.correx.core.events.events.ChatTurnEvent
import com.correx.core.events.events.L3MemoryRetrievedEvent
import com.correx.core.events.events.OrchestrationPausedEvent
import com.correx.core.events.events.OrchestrationResumedEvent
import com.correx.core.events.events.StageCompletedEvent
import com.correx.core.events.events.StageFailedEvent
import com.correx.core.events.events.SteeringNoteAddedEvent
import com.correx.core.events.events.StoredEvent
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.talkie.model.RouterL2Entry
import com.correx.core.talkie.model.TalkieState
import com.correx.core.talkie.model.TalkieTurn
import com.correx.core.talkie.model.StageOutcomeKind
import com.correx.core.talkie.model.TurnRole
import com.correx.core.talkie.model.WorkflowStatus
import kotlinx.datetime.Instant

interface TalkieReducer {
    val initial: TalkieState
    fun reduce(state: TalkieState, event: StoredEvent): TalkieState
}

class DefaultTalkieReducer : TalkieReducer {

    override val initial: TalkieState = TalkieState(
        sessionId = null,
        workflowStatus = WorkflowStatus.IDLE,
        currentStageId = null,
        l2Memory = emptyList(),
        conversationHistory = emptyList(),
    )

    override fun reduce(state: TalkieState, event: StoredEvent): TalkieState {
        return when (val payload = event.payload) {
            is WorkflowStartedEvent -> handleWorkflowStarted(state, event)
            is WorkflowCompletedEvent -> handleWorkflowCompleted(state)
            is WorkflowFailedEvent -> handleWorkflowFailed(state)
            is OrchestrationPausedEvent -> handleOrchestrationPaused(state)
            is OrchestrationResumedEvent -> handleOrchestrationResumed(state)
            is StageCompletedEvent -> handleStageCompleted(state, event)
            is StageFailedEvent -> handleStageFailed(state, event)
            is SteeringNoteAddedEvent -> handleSteeringNote(state, payload)
            is ChatTurnEvent -> handleChatTurn(state, event)
            is L3MemoryRetrievedEvent -> state.copy(lastRetrievedMemory = payload.hits)
            else -> state
        }
    }

    private fun handleWorkflowStarted(state: TalkieState, event: StoredEvent): TalkieState {
        val payload = event.payload as WorkflowStartedEvent
        return state.copy(
            sessionId = payload.sessionId,
            workflowStatus = WorkflowStatus.RUNNING,
            currentStageId = payload.startStageId
        )
    }

    private fun handleWorkflowCompleted(state: TalkieState): TalkieState {
        return state.copy(
            workflowStatus = WorkflowStatus.COMPLETED,
            currentStageId = null
        )
    }

    private fun handleWorkflowFailed(state: TalkieState): TalkieState {
        return state.copy(
            workflowStatus = WorkflowStatus.FAILED,
            currentStageId = null
        )
    }

    private fun handleOrchestrationPaused(state: TalkieState): TalkieState {
        return state.copy(
            workflowStatus = WorkflowStatus.PAUSED
        )
    }

    private fun handleOrchestrationResumed(state: TalkieState): TalkieState {
        return state.copy(
            workflowStatus = WorkflowStatus.RUNNING
        )
    }

    private fun handleStageCompleted(state: TalkieState, event: StoredEvent): TalkieState {
        val payload = event.payload as StageCompletedEvent
        val entry = RouterL2Entry(
            stageId = payload.stageId,
            summary = "Stage ${payload.stageId.value} completed",
            outcome = StageOutcomeKind.SUCCESS,
            timestamp = event.metadata.timestamp,
            steeringNotes = state.pendingSteeringNotes,
        )
        return state.copy(
            l2Memory = state.l2Memory + entry,
            pendingSteeringNotes = emptyList(),
        )
    }

    private fun handleStageFailed(state: TalkieState, event: StoredEvent): TalkieState {
        val payload = event.payload as StageFailedEvent
        val entry = RouterL2Entry(
            stageId = payload.stageId,
            summary = "Stage ${payload.stageId.value} failed",
            outcome = StageOutcomeKind.FAILURE,
            timestamp = event.metadata.timestamp,
            reason = payload.reason,
            steeringNotes = state.pendingSteeringNotes,
        )
        return state.copy(
            l2Memory = state.l2Memory + entry,
            currentStageId = null,
            pendingSteeringNotes = emptyList(),
        )
    }

    // adr-0003 §4: harvest user steering into the current stage's decision point.
    // Accumulate here; handleStageCompleted/Failed attach and clear. Pure field
    // extraction from the event stream — no inference.
    private fun handleSteeringNote(state: TalkieState, payload: SteeringNoteAddedEvent): TalkieState =
        state.copy(pendingSteeringNotes = state.pendingSteeringNotes + payload.content)

    private fun handleChatTurn(state: TalkieState, event: StoredEvent): TalkieState {
        val payload = event.payload as ChatTurnEvent
        val turnRole = when (payload.role) {
            com.correx.core.events.events.ChatTurnRole.USER -> TurnRole.USER
            com.correx.core.events.events.ChatTurnRole.ROUTER -> TurnRole.ROUTER
        }
        val turn = TalkieTurn(
            role = turnRole,
            content = payload.content,
            timestamp = Instant.fromEpochMilliseconds(payload.timestampMs),
            turnId = payload.turnId,
        )
        return state.copy(
            conversationHistory = state.conversationHistory + turn
        )
    }
}
