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.Server.Config.ClientContext (ClientContext)
import LaunchDarkly.Server.Client.Status        (Status, transitionStatus)
import LaunchDarkly.Server.Features             (Segment, Flag)
import LaunchDarkly.Server.Store.Internal       (initializeStore, insertFlag, insertSegment, deleteFlag, deleteSegment, StoreHandle)
import LaunchDarkly.AesonCompat                 (KeyMap)

type DataSourceFactory = ClientContext -> DataSourceUpdates -> IO DataSource

nullDataSourceFactory :: DataSourceFactory
nullDataSourceFactory :: DataSourceFactory
nullDataSourceFactory ClientContext
_ DataSourceUpdates
_ =
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ IO Bool -> IO () -> IO () -> DataSource
DataSource (forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False) (forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (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 IORef Status
status StoreHandle IO
store =
    let modifyStatus :: Status -> IO ()
modifyStatus Status
status' = forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef Status
status (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,()) (Status -> Status -> Status
transitionStatus Status
status')) 
    in DataSourceUpdates
        { $sel:dataSourceUpdatesInit:DataSourceUpdates :: KeyMap Flag -> KeyMap Segment -> IO (Either Text ())
dataSourceUpdatesInit = 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 = forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Flag -> StoreResultM m ()
insertFlag StoreHandle IO
store 
        , $sel:dataSourceUpdatesInsertSegment:DataSourceUpdates :: Segment -> IO (Either Text ())
dataSourceUpdatesInsertSegment = 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 = 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 = 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 
        }