module LaunchDarkly.Server.Client.Internal
    ( Client (..)
    , Status (..)
    , clientVersion
    , setStatus
    , getStatusI
    ) where

import Control.Concurrent (ThreadId)
import Control.Concurrent.MVar (MVar)
import Data.Generics.Product (getField)
import Data.IORef (IORef, atomicModifyIORef', readIORef)
import Data.Text (Text)
import GHC.Generics (Generic)

import LaunchDarkly.Server.Client.Status (Status (..), transitionStatus)
import LaunchDarkly.Server.Config.Internal (Config)
import LaunchDarkly.Server.DataSource.Internal (DataSource)
import LaunchDarkly.Server.Events (EventState)
import LaunchDarkly.Server.Store.Internal (StoreHandle, getInitializedC)

-- | The version string for this library.
clientVersion :: Text
clientVersion :: Text
clientVersion = Text
"4.0.0"

-- |
-- Client is the LaunchDarkly client. Client instances are thread-safe.
-- Applications should instantiate a single instance for the lifetime of their
-- application.
data Client = Client
    { Client -> Config
config :: !(Config)
    , Client -> StoreHandle IO
store :: !(StoreHandle IO)
    , Client -> IORef Status
status :: !(IORef Status)
    , Client -> EventState
events :: !EventState
    , Client -> Maybe (ThreadId, MVar ())
eventThreadPair :: !(Maybe (ThreadId, MVar ()))
    , Client -> DataSource
dataSource :: !DataSource
    }
    deriving (forall x. Rep Client x -> Client
forall x. Client -> Rep Client x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Client x -> Client
$cfrom :: forall x. Client -> Rep Client x
Generic)

setStatus :: Client -> Status -> IO ()
setStatus :: Client -> Status -> IO ()
setStatus Client
client Status
status' =
    forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"status" Client
client) (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,()) (Status -> Status -> Status
transitionStatus Status
status'))

getStatusI :: Client -> IO Status
getStatusI :: Client -> IO Status
getStatusI Client
client =
    forall a. IORef a -> IO a
readIORef (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"status" Client
client) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Status
Unauthorized -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Status
Unauthorized
        Status
ShuttingDown -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Status
ShuttingDown
        Status
_ ->
            forall store (m :: * -> *).
LaunchDarklyStoreRead store m =>
store -> StoreResultM m Bool
getInitializedC (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"store" Client
client) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
                Right Bool
True -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Status
Initialized
                Either Text Bool
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure Status
Uninitialized