package com.correx.apps.server.logging

import com.correx.core.events.events.NewEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.stores.EventStore
import com.correx.core.events.types.SessionId
import kotlinx.coroutines.flow.Flow
import org.slf4j.LoggerFactory

private val log = LoggerFactory.getLogger(LoggingEventStore::class.java)

class LoggingEventStore(private val delegate: EventStore) : EventStore {

    override suspend fun append(event: NewEvent): StoredEvent =
        runCatching { delegate.append(event) }
            .onSuccess { stored ->
                log.info(
                    "event emitted session={} type={} id={}",
                    event.metadata.sessionId.value,
                    event.payload::class.simpleName,
                    stored.metadata.eventId.value,
                )
            }
            .onFailure { ex ->
                log.error(
                    "append failed session={} type={}",
                    event.metadata.sessionId.value,
                    event.payload::class.simpleName,
                    ex,
                )
            }
            .getOrThrow()

    override suspend fun appendAll(events: List<NewEvent>): List<StoredEvent> =
        runCatching { delegate.appendAll(events) }
            .onSuccess { stored ->
                val breakdown = events.groupingBy { it.payload::class.simpleName }.eachCount()
                log.info("events emitted count={} types={}", stored.size, breakdown)
                stored.forEach { s ->
                    log.debug(
                        "event emitted session={} type={} id={}",
                        s.metadata.sessionId.value,
                        s.payload::class.simpleName,
                        s.metadata.eventId.value,
                    )
                }
            }
            .onFailure { ex ->
                log.error("appendAll failed count={}", events.size, ex)
            }
            .getOrThrow()

    override fun read(sessionId: SessionId): List<StoredEvent> = delegate.read(sessionId)

    override fun readFrom(sessionId: SessionId, fromSequence: Long): List<StoredEvent> =
        delegate.readFrom(sessionId, fromSequence)

    override fun lastSequence(sessionId: SessionId): Long? = delegate.lastSequence(sessionId)

    override fun subscribe(sessionId: SessionId): Flow<StoredEvent> = delegate.subscribe(sessionId)

    override fun allEvents(): Sequence<StoredEvent> = delegate.allEvents()
    override fun allSessionIds(): Set<SessionId> =
        delegate.allSessionIds().also { log.debug("got session ids from store: {}", it) }

    override fun subscribeAll(): Flow<StoredEvent> = delegate.subscribeAll()

    override suspend fun lastGlobalSequence(): Long = delegate.lastGlobalSequence()
}
