module IHP.DataSync.Types where

import IHP.Prelude
import Data.Aeson
import IHP.DataSync.DynamicQuery
import qualified Database.PostgreSQL.Simple as PG
import Control.Concurrent.MVar as MVar


data DataSyncMessage
    = DataSyncQuery { DataSyncMessage -> DynamicSQLQuery
query :: !DynamicSQLQuery, DataSyncMessage -> Int
requestId :: !Int, DataSyncMessage -> Maybe UUID
transactionId :: !(Maybe UUID) }
    | CreateDataSubscription { query :: !DynamicSQLQuery, requestId :: !Int }
    | DeleteDataSubscription { DataSyncMessage -> UUID
subscriptionId :: !UUID, requestId :: !Int }
    | CreateRecordMessage { DataSyncMessage -> Text
table :: !Text, DataSyncMessage -> HashMap Text Value
record :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
    | CreateRecordsMessage { table :: !Text, DataSyncMessage -> [HashMap Text Value]
records :: ![HashMap Text Value], requestId :: !Int, transactionId :: !(Maybe UUID) }
    | UpdateRecordMessage { table :: !Text, DataSyncMessage -> UUID
id :: !UUID, DataSyncMessage -> HashMap Text Value
patch :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
    | UpdateRecordsMessage { table :: !Text, DataSyncMessage -> [UUID]
ids :: ![UUID], patch :: !(HashMap Text Value), requestId :: !Int, transactionId :: !(Maybe UUID) }
    | DeleteRecordMessage { table :: !Text, id :: !UUID, requestId :: !Int, transactionId :: !(Maybe UUID) }
    | DeleteRecordsMessage { table :: !Text, ids :: ![UUID], requestId :: !Int, transactionId :: !(Maybe UUID) }
    | StartTransaction { requestId :: !Int }
    | RollbackTransaction { requestId :: !Int, id :: !UUID }
    | CommitTransaction { requestId :: !Int, id :: !UUID }
    | LoginWithEmailAndPassword { requestId :: !Int, DataSyncMessage -> Text
email :: !Text, DataSyncMessage -> Text
password :: !Text }
    | LoginWithJWT { requestId :: !Int, DataSyncMessage -> Text
jwt :: !Text }
    | CreateUser { requestId :: !Int, email :: !Text, password :: !Text }
    | ConfirmUser { requestId :: !Int, DataSyncMessage -> UUID
userId :: !UUID, DataSyncMessage -> Text
token :: !Text }
    deriving (DataSyncMessage -> DataSyncMessage -> Bool
(DataSyncMessage -> DataSyncMessage -> Bool)
-> (DataSyncMessage -> DataSyncMessage -> Bool)
-> Eq DataSyncMessage
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DataSyncMessage -> DataSyncMessage -> Bool
== :: DataSyncMessage -> DataSyncMessage -> Bool
$c/= :: DataSyncMessage -> DataSyncMessage -> Bool
/= :: DataSyncMessage -> DataSyncMessage -> Bool
Eq, Int -> DataSyncMessage -> ShowS
[DataSyncMessage] -> ShowS
DataSyncMessage -> String
(Int -> DataSyncMessage -> ShowS)
-> (DataSyncMessage -> String)
-> ([DataSyncMessage] -> ShowS)
-> Show DataSyncMessage
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DataSyncMessage -> ShowS
showsPrec :: Int -> DataSyncMessage -> ShowS
$cshow :: DataSyncMessage -> String
show :: DataSyncMessage -> String
$cshowList :: [DataSyncMessage] -> ShowS
showList :: [DataSyncMessage] -> ShowS
Show)

data DataSyncResponse
    = DataSyncResult { DataSyncResponse -> [[Field]]
result :: ![[Field]], DataSyncResponse -> Int
requestId :: !Int }
    | DataSyncError { requestId :: !Int, DataSyncResponse -> Text
errorMessage :: !Text }
    | FailedToDecodeMessageError { errorMessage :: !Text }
    | DidCreateDataSubscription { requestId :: !Int, DataSyncResponse -> UUID
subscriptionId :: !UUID, result :: ![[Field]] }
    | DidDeleteDataSubscription { requestId :: !Int, subscriptionId :: !UUID }
    | DidInsert { subscriptionId :: !UUID, DataSyncResponse -> [Field]
record :: ![Field] }
    | DidUpdate { subscriptionId :: !UUID, DataSyncResponse -> UUID
id :: UUID, DataSyncResponse -> Value
changeSet :: !Value }
    | DidDelete { subscriptionId :: !UUID, id :: !UUID }
    | DidCreateRecord { requestId :: !Int, record :: ![Field] } -- ^ Response to 'CreateRecordMessage'
    | DidCreateRecords { requestId :: !Int, DataSyncResponse -> [[Field]]
records :: ![[Field]] } -- ^ Response to 'CreateRecordsMessage'
    | DidUpdateRecord { requestId :: !Int, record :: ![Field] } -- ^ Response to 'UpdateRecordMessage'
    | DidUpdateRecords { requestId :: !Int, records :: ![[Field]] } -- ^ Response to 'UpdateRecordsMessage'
    | DidDeleteRecord { requestId :: !Int }
    | DidDeleteRecords { requestId :: !Int }
    | DidStartTransaction { requestId :: !Int, DataSyncResponse -> UUID
transactionId :: !UUID }
    | DidRollbackTransaction { requestId :: !Int, transactionId :: !UUID }
    | DidCommitTransaction { requestId :: !Int, transactionId :: !UUID }

    | LoginSuccessful { requestId :: !Int, DataSyncResponse -> UUID
userId :: !UUID, DataSyncResponse -> Text
jwt :: !Text }
    | UserLocked { requestId :: !Int }
    | UserUnconfirmed { requestId :: !Int }
    | InvalidCredentials { requestId :: !Int }

    | DidCreateUser { requestId :: !Int, userId :: !UUID, DataSyncResponse -> Bool
emailConfirmationRequired :: !Bool, jwt :: !Text }
    | CreateUserFailed { requestId :: !Int, DataSyncResponse -> [(Text, Text)]
validationFailures :: [(Text, Text)] }
    | DidConfirmUser { requestId :: !Int, jwt :: !Text }
    | DidConfirmUserAlready { requestId :: !Int }
    | ConfirmUserFailed { requestId :: !Int }

data GraphQLResult = GraphQLResult { GraphQLResult -> UndecodedJSON
graphQLResult :: !UndecodedJSON, GraphQLResult -> Int
requestId :: !Int }

data DataSyncTransaction
    = DataSyncTransaction
    { DataSyncTransaction -> UUID
id :: !UUID
    , DataSyncTransaction -> Connection
connection :: !PG.Connection
    , DataSyncTransaction -> MVar ()
close :: MVar ()
    }

data DataSyncController
    = DataSyncController
    | DataSyncReady
        { DataSyncController -> HashMap UUID (MVar ())
subscriptions :: !(HashMap UUID (MVar.MVar ()))
        , DataSyncController -> HashMap UUID DataSyncTransaction
transactions :: !(HashMap UUID DataSyncTransaction)
        , DataSyncController -> [Async ()]
asyncs :: ![Async ()]
        }