module LaunchDarkly.Server.DataSource.Internal
    ( DataSourceFactory
    , nullDataSourceFactory
    , DataSource (..)
    , DataSourceUpdates (..)
    , defaultDataSourceUpdates
    )
where

import Data.IORef (IORef, atomicModifyIORef')
import Data.Text (Text)
import GHC.Natural (Natural)

import LaunchDarkly.AesonCompat (KeyMap)
import LaunchDarkly.Server.Client.Status (Status, transitionStatus)
import LaunchDarkly.Server.Config.ClientContext (ClientContext)
import LaunchDarkly.Server.Features (Flag, Segment)
import LaunchDarkly.Server.Store.Internal (StoreHandle, deleteFlag, deleteSegment, initializeStore, insertFlag, insertSegment)

type DataSourceFactory = ClientContext -> DataSourceUpdates -> IO DataSource

nullDataSourceFactory :: DataSourceFactory
nullDataSourceFactory :: DataSourceFactory
nullDataSourceFactory _ _ =
    DataSource -> IO DataSource
forall (f :: * -> *) a. Applicative f => a -> f a
pure (DataSource -> IO DataSource) -> DataSource -> IO DataSource
forall a b. (a -> b) -> a -> b
$ IO Bool -> IO () -> IO () -> DataSource
DataSource (Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False) (() -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (() -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())

data DataSource = DataSource
    { DataSource -> IO Bool
dataSourceIsInitialized :: IO Bool
    , DataSource -> IO ()
dataSourceStart :: IO ()
    , DataSource -> IO ()
dataSourceStop :: IO ()
    }

data DataSourceUpdates = DataSourceUpdates
    { DataSourceUpdates
-> KeyMap Flag -> KeyMap Segment -> IO (Either Text ())
dataSourceUpdatesInit :: !(KeyMap Flag -> KeyMap Segment -> IO (Either Text ()))
    , DataSourceUpdates -> Flag -> IO (Either Text ())
dataSourceUpdatesInsertFlag :: !(Flag -> IO (Either Text ()))
    , DataSourceUpdates -> Segment -> IO (Either Text ())
dataSourceUpdatesInsertSegment :: !(Segment -> IO (Either Text ()))
    , DataSourceUpdates -> Text -> Natural -> IO (Either Text ())
dataSourceUpdatesDeleteFlag :: !(Text -> Natural -> IO (Either Text ()))
    , DataSourceUpdates -> Text -> Natural -> IO (Either Text ())
dataSourceUpdatesDeleteSegment :: !(Text -> Natural -> IO (Either Text ()))
    , DataSourceUpdates -> Status -> IO ()
dataSourceUpdatesSetStatus :: Status -> IO ()
    }

defaultDataSourceUpdates :: IORef Status -> StoreHandle IO -> DataSourceUpdates
defaultDataSourceUpdates :: IORef Status -> StoreHandle IO -> DataSourceUpdates
defaultDataSourceUpdates status :: IORef Status
status store :: StoreHandle IO
store =
    let modifyStatus :: Status -> IO ()
modifyStatus status' :: Status
status' = IORef Status -> (Status -> (Status, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef Status
status ((Status -> (Status, ()))
-> (Status -> Status) -> Status -> (Status, ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,()) (Status -> Status -> Status
transitionStatus Status
status'))
     in $WDataSourceUpdates :: (KeyMap Flag -> KeyMap Segment -> IO (Either Text ()))
-> (Flag -> IO (Either Text ()))
-> (Segment -> IO (Either Text ()))
-> (Text -> Natural -> IO (Either Text ()))
-> (Text -> Natural -> IO (Either Text ()))
-> (Status -> IO ())
-> DataSourceUpdates
DataSourceUpdates
            { $sel:dataSourceUpdatesInit:DataSourceUpdates :: KeyMap Flag -> KeyMap Segment -> IO (Either Text ())
dataSourceUpdatesInit = StoreHandle IO
-> KeyMap Flag -> KeyMap Segment -> IO (Either Text ())
forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> KeyMap Flag -> KeyMap Segment -> StoreResultM m ()
initializeStore StoreHandle IO
store
            , $sel:dataSourceUpdatesInsertFlag:DataSourceUpdates :: Flag -> IO (Either Text ())
dataSourceUpdatesInsertFlag = StoreHandle IO -> Flag -> IO (Either Text ())
forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Flag -> StoreResultM m ()
insertFlag StoreHandle IO
store
            , $sel:dataSourceUpdatesInsertSegment:DataSourceUpdates :: Segment -> IO (Either Text ())
dataSourceUpdatesInsertSegment = StoreHandle IO -> Segment -> IO (Either Text ())
forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Segment -> StoreResultM m ()
insertSegment StoreHandle IO
store
            , $sel:dataSourceUpdatesDeleteFlag:DataSourceUpdates :: Text -> Natural -> IO (Either Text ())
dataSourceUpdatesDeleteFlag = StoreHandle IO -> Text -> Natural -> IO (Either Text ())
forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Text -> Natural -> StoreResultM m ()
deleteFlag StoreHandle IO
store
            , $sel:dataSourceUpdatesDeleteSegment:DataSourceUpdates :: Text -> Natural -> IO (Either Text ())
dataSourceUpdatesDeleteSegment = StoreHandle IO -> Text -> Natural -> IO (Either Text ())
forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Text -> Natural -> StoreResultM m ()
deleteSegment StoreHandle IO
store
            , $sel:dataSourceUpdatesSetStatus:DataSourceUpdates :: Status -> IO ()
dataSourceUpdatesSetStatus = Status -> IO ()
modifyStatus
            }