module Signet.Unstable.Type.Message where

import qualified Data.Bifunctor as Bifunctor
import qualified Data.ByteString as ByteString
import qualified Signet.Unstable.Exception.InvalidMessage as InvalidMessage
import qualified Signet.Unstable.Type.Id as Id
import qualified Signet.Unstable.Type.Payload as Payload
import qualified Signet.Unstable.Type.Timestamp as Timestamp

data Message = MkMessage
  { Message -> Id
id_ :: Id.Id,
    Message -> Timestamp
timestamp :: Timestamp.Timestamp,
    Message -> Payload
payload :: Payload.Payload
  }
  deriving (Message -> Message -> Bool
(Message -> Message -> Bool)
-> (Message -> Message -> Bool) -> Eq Message
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Message -> Message -> Bool
== :: Message -> Message -> Bool
$c/= :: Message -> Message -> Bool
/= :: Message -> Message -> Bool
Eq, Int -> Message -> ShowS
[Message] -> ShowS
Message -> String
(Int -> Message -> ShowS)
-> (Message -> String) -> ([Message] -> ShowS) -> Show Message
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Message -> ShowS
showsPrec :: Int -> Message -> ShowS
$cshow :: Message -> String
show :: Message -> String
$cshowList :: [Message] -> ShowS
showList :: [Message] -> ShowS
Show)

parse :: ByteString.ByteString -> Either InvalidMessage.InvalidMessage Message
parse :: ByteString -> Either InvalidMessage Message
parse ByteString
x = do
  let (ByteString
rawId, ByteString
y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
ByteString.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Id.separator) ByteString
x
  Id
theId <- (InvalidId -> InvalidMessage)
-> Either InvalidId Id -> Either InvalidMessage Id
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
Bifunctor.first InvalidId -> InvalidMessage
InvalidMessage.InvalidId (Either InvalidId Id -> Either InvalidMessage Id)
-> Either InvalidId Id -> Either InvalidMessage Id
forall a b. (a -> b) -> a -> b
$ ByteString -> Either InvalidId Id
Id.parse ByteString
rawId
  let (ByteString
rawTimestamp, ByteString
z) =
        (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
ByteString.break (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Id.separator) (ByteString -> (ByteString, ByteString))
-> ByteString -> (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$
          Int -> ByteString -> ByteString
ByteString.drop Int
1 ByteString
y
  Timestamp
theTimestamp <-
    (InvalidTimestamp -> InvalidMessage)
-> Either InvalidTimestamp Timestamp
-> Either InvalidMessage Timestamp
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
Bifunctor.first InvalidTimestamp -> InvalidMessage
InvalidMessage.InvalidTimestamp (Either InvalidTimestamp Timestamp
 -> Either InvalidMessage Timestamp)
-> Either InvalidTimestamp Timestamp
-> Either InvalidMessage Timestamp
forall a b. (a -> b) -> a -> b
$
      ByteString -> Either InvalidTimestamp Timestamp
Timestamp.parse ByteString
rawTimestamp
  let thePayload :: Payload
thePayload = ByteString -> Payload
Payload.MkPayload (ByteString -> Payload) -> ByteString -> Payload
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
ByteString.drop Int
1 ByteString
z
  Message -> Either InvalidMessage Message
forall a. a -> Either InvalidMessage a
forall (f :: * -> *) a. Applicative f => a -> f a
pure MkMessage {id_ :: Id
id_ = Id
theId, timestamp :: Timestamp
timestamp = Timestamp
theTimestamp, payload :: Payload
payload = Payload
thePayload}

render :: Message -> ByteString.ByteString
render :: Message -> ByteString
render Message
message =
  Id -> ByteString
Id.render (Message -> Id
id_ Message
message)
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word8 -> ByteString
ByteString.singleton Word8
Id.separator
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Timestamp -> ByteString
Timestamp.render (Message -> Timestamp
timestamp Message
message)
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Word8 -> ByteString
ByteString.singleton Word8
Id.separator
    ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Payload -> ByteString
Payload.unwrap (Message -> Payload
payload Message
message)