content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE NamedFieldPuns #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Subscription.Case.Publishing
    ( testPublishing,
    )
  where
  
  import Data.ByteString.Lazy.Char8
    ( ByteString,
    )
  import Data.Morpheus.Subscriptions
    ( Event (..),
    )
  import Data.Morpheus.Subscriptions.Internal
    ( Input,
      SUB,
      connect,
      empty,
    )
  import Subscription.API
    ( Channel (..),
      EVENT,
      Info (..),
      app,
    )
  import Subscription.Utils
    ( SimulationState (..),
      apolloConnectionAck,
      apolloInit,
      apolloRes,
      apolloStart,
      apolloStop,
      inputsAreConsumed,
      simulate,
      simulatePublish,
      storeSubscriptions,
      testResponse,
    )
  import Test.Tasty
    ( TestTree,
      testGroup,
    )
  import Prelude
  
  startNewDeity :: ByteString -> ByteString
  startNewDeity = apolloStart "subscription MySubscription { newDeity { name , age }}"
  
  startNewHuman :: ByteString -> ByteString
  startNewHuman = apolloStart "subscription MySubscription { newHuman { name , age }}"
  
  simulateSubscriptions :: IO (Input SUB, SimulationState EVENT)
  simulateSubscriptions = do
    input <- connect
    state <-
      simulate
        app
        input
        ( SimulationState
            [ apolloInit,
              startNewDeity "1",
              startNewDeity "2",
              startNewDeity "3",
              startNewHuman "4",
              apolloStop "1"
            ]
            []
            empty
        )
    pure (input, state)
  
  triggerSubscription ::
    IO TestTree
  triggerSubscription = do
    (input, state) <- simulateSubscriptions
    SimulationState {inputs, outputs, store} <-
      simulatePublish (Event [DEITY] Info {name = "Zeus", age = 1200}) state
        >>= simulatePublish (Event [HUMAN] Info {name = "Hercules", age = 18})
    pure
      $ testGroup
        "publish event"
        [ inputsAreConsumed inputs,
          testResponse
            -- triggers subscriptions by channels
            [ apolloConnectionAck,
              apolloRes
                "2"
                "{\"newDeity\":{\"name\":\"Zeus\",\"age\":1200}}",
              apolloRes
                "3"
                "{\"newDeity\":{\"name\":\"Zeus\",\"age\":1200}}",
              apolloRes
                "4"
                "{\"newHuman\":{\"name\":\"Hercules\",\"age\":18}}"
            ]
            outputs,
          storeSubscriptions
            input
            ["2", "3", "4"]
            store
        ]
  
  testPublishing :: IO TestTree
  testPublishing = do
    trigger <- triggerSubscription
    return $ testGroup "Publishing" [trigger]
  