{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}

{- |
Module      : Test.Hindsight.Store.Common
Description : Common utilities and types for event store tests
Copyright   : (c) 2025
License     : BSD3
Maintainer  : gael@hindsight.events
Stability   : experimental

Shared test utilities, helper functions, and types used across all event store
backend test suites.
-}
module Test.Hindsight.Store.Common where

import Control.Concurrent (MVar, putMVar)
import Data.IORef (IORef, atomicModifyIORef')
import Hindsight.Events (CurrentPayloadType)
import Hindsight.Store (EventEnvelope (EventWithMetadata), EventHandler, SubscriptionResult (Continue, Stop))

-- * Event Handler Helpers

-- | Collect events into an IORef (generic over event type)
collectEvents :: IORef [EventEnvelope event backend] -> EventHandler event IO backend
collectEvents :: forall (event :: Symbol) backend.
IORef [EventEnvelope event backend]
-> EventHandler event IO backend
collectEvents IORef [EventEnvelope event backend]
ref EventEnvelope event backend
event = do
    IORef [EventEnvelope event backend]
-> ([EventEnvelope event backend]
    -> ([EventEnvelope event backend], ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef [EventEnvelope event backend]
ref (\[EventEnvelope event backend]
events -> (EventEnvelope event backend
event EventEnvelope event backend
-> [EventEnvelope event backend] -> [EventEnvelope event backend]
forall a. a -> [a] -> [a]
: [EventEnvelope event backend]
events, ()))
    SubscriptionResult -> IO SubscriptionResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SubscriptionResult
Continue

-- | Handle tombstone event by signaling completion (generic over any event type)
handleTombstone :: MVar () -> EventHandler event IO backend
handleTombstone :: forall (event :: Symbol) backend.
MVar () -> EventHandler event IO backend
handleTombstone MVar ()
completionVar EventEnvelope event backend
_ = do
    MVar () -> () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar ()
completionVar ()
    SubscriptionResult -> IO SubscriptionResult
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure SubscriptionResult
Stop

-- | Extract payload from event envelope (no cast needed - type guaranteed!)
extractPayload :: EventEnvelope event backend -> CurrentPayloadType event
extractPayload :: forall (event :: Symbol) backend.
EventEnvelope event backend -> CurrentPayloadType event
extractPayload (EventWithMetadata Cursor backend
_ EventId
_ StreamId
_ StreamVersion
_ Maybe CorrelationId
_ UTCTime
_ CurrentPayloadType event
payload) = CurrentPayloadType event
payload