package com.correx.core.approvals

import com.correx.core.approvals.model.ApprovalContext
import com.correx.core.approvals.model.ApprovalDecision
import com.correx.core.approvals.model.ApprovalGrant
import com.correx.core.approvals.model.ApprovalScopeIdentity
import com.correx.core.approvals.model.ApprovalState
import com.correx.core.approvals.model.DomainApprovalRequest
import com.correx.core.events.events.ApprovalDecisionResolvedEvent
import com.correx.core.events.events.ApprovalGrantCreatedEvent
import com.correx.core.events.events.ApprovalGrantExpiredEvent
import com.correx.core.events.events.ApprovalRequestedEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.sessions.ApprovalMode

class DefaultApprovalReducer : ApprovalReducer {

    override fun reduce(state: ApprovalState, event: StoredEvent): ApprovalState {
        return when (val payload = event.payload) {
            is ApprovalRequestedEvent -> {
                val request = DomainApprovalRequest(
                    id = payload.requestId,
                    tier = payload.tier,
                    validationReportId = payload.validationReportId,
                    riskSummaryId = payload.riskSummaryId,
                    timestamp = event.metadata.timestamp,
                    causationId = event.metadata.causationId,
                    correlationId = event.metadata.correlationId,
                    userSteering = payload.userSteering,
                    toolName = payload.toolName,
                    preview = payload.preview,
                )
                state.copy(requests = state.requests + (request.id to request))
            }

            is ApprovalDecisionResolvedEvent -> {
                val decisionId = payload.decisionId
                // The event does not carry context info, so we reconstruct a partial identity
                // with a default mode; stageId and projectId are unavailable at this point.
                val contextSnapshot = ApprovalContext(
                    identity = ApprovalScopeIdentity(
                        sessionId = event.metadata.sessionId,
                        stageId = null,
                        projectId = null,
                    ),
                    mode = ApprovalMode.PROMPT,
                    causationId = event.metadata.causationId,
                    correlationId = event.metadata.correlationId,
                )
                val decision = ApprovalDecision(
                    id = decisionId,
                    requestId = payload.requestId,
                    outcome = payload.outcome,
                    state = payload.status,
                    tier = payload.tier,
                    contextSnapshot = contextSnapshot,
                    resolutionTimestamp = payload.resolutionTimestamp,
                    reason = payload.reason,
                    userSteering = payload.userSteering,
                )
                state.copy(decisions = state.decisions + (decisionId to decision))
            }

            is ApprovalGrantCreatedEvent -> {
                val grant = ApprovalGrant(
                    id = payload.grantId,
                    scope = payload.scope,
                    permittedTiers = payload.permittedTiers,
                    reason = payload.reason,
                    timestamp = event.metadata.timestamp,
                    expiresAt = payload.expiresAt,
                )
                state.copy(grants = state.grants + (grant.id to grant))
            }

            is ApprovalGrantExpiredEvent -> {
                state.copy(grants = state.grants - payload.grantId)
            }

            else -> state
        }
    }
}
