content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module NamedResolvers
    ( runNamedResolversTest,
    )
  where
  
  import qualified Data.ByteString.Lazy.Char8 as LBS
  import Data.Morpheus.App
    ( App (..),
      mkApp,
      runApp,
    )
  import Data.Morpheus.App.Internal.Resolving (resultOr)
  import Data.Morpheus.App.NamedResolvers
    ( NamedResolverFunction,
      RootResolverValue,
      enum,
      getArgument,
      list,
      object,
      queryResolvers,
      ref,
      refs,
      variant,
    )
  import Data.Morpheus.Core
    ( parseSchema,
    )
  import Data.Morpheus.Types.IO
    ( GQLRequest (..),
      GQLResponse,
    )
  import Data.Morpheus.Types.Internal.AST
    ( QUERY,
      Schema,
      VALID,
    )
  import Relude hiding (ByteString)
  import Test.Morpheus
    ( FileUrl,
      testApi,
    )
  import Test.Tasty
    ( TestTree,
    )
  
  -- DEITIES
  resolverDeities :: (Monad m) => RootResolverValue e m
  resolverDeities =
    queryResolvers
      [ ( "Query",
          traverse
            ( const
                $ object
                  [ ("deity", ref "Deity" <$> getArgument "id"),
                    ("deities", pure $ refs "Deity" ["zeus", "morpheus"])
                  ]
            )
        ),
        ("Deity", deityResolver)
      ]
  
  deityResolver :: (Monad m) => NamedResolverFunction QUERY e m
  deityResolver = traverse deityRes
    where
      deityRes "zeus" =
        object
          [ ("name", pure "Zeus"),
            ("power", pure $ list [])
          ]
      deityRes _ =
        object
          [ ("name", pure "Morpheus"),
            ("power", pure $ list [enum "Shapeshifting"])
          ]
  
  -- REALMS
  resolverRealms :: (Monad m) => RootResolverValue e m
  resolverRealms =
    queryResolvers
      [ ( "Query",
          traverse
            ( const
                $ object
                  [ ("realm", ref "Realm" <$> getArgument "id"),
                    ("realms", pure $ refs "Realm" ["olympus", "dreams"])
                  ]
            )
        ),
        ("Deity", deityResolverExt),
        ("Realm", realmResolver)
      ]
  
  deityResolverExt :: (Monad m) => NamedResolverFunction QUERY e m
  deityResolverExt = traverse deityExt
    where
      deityExt "zeus" = object [("realm", pure $ ref "Realm" "olympus")]
      deityExt "morpheus" = object [("realm", pure $ ref "Realm" "dreams")]
      deityExt _ = object []
  
  realmResolver :: (Monad m) => NamedResolverFunction QUERY e m
  realmResolver = traverse realmResolver'
    where
      realmResolver' "olympus" =
        object
          [ ("name", pure "Mount Olympus"),
            ("owner", pure $ ref "Deity" "zeus")
          ]
      realmResolver' "dreams" =
        object
          [ ("name", pure "Fictional world of dreams"),
            ("owner", pure $ ref "Deity" "morpheus")
          ]
      realmResolver' _ =
        object
          [ ("name", pure "None")
          ]
  
  -- ENTITIES
  resolverEntities :: (Monad m) => RootResolverValue e m
  resolverEntities =
    queryResolvers
      [ ( "Query",
          traverse
            ( const
                $ object
                  [ ("entity", ref "Entity" <$> getArgument "id"),
                    ( "entities",
                      pure
                        $ refs
                          "Entity"
                          ["zeus", "morpheus", "olympus", "dreams"]
                    )
                  ]
            )
        ),
        ("Entity", resolveEntity)
      ]
  
  resolveEntity :: (Monad m) => NamedResolverFunction QUERY e m
  resolveEntity = traverse resEntity
    where
      resEntity "zeus" = variant "Deity" "zeus"
      resEntity "morpheus" = variant "Deity" "morpheus"
      resEntity "olympus" = variant "Realm" "olympus"
      resEntity "dreams" = variant "Realm" "dreams"
      resEntity _ = object []
  
  getSchema :: String -> IO (Schema VALID)
  getSchema url = LBS.readFile url >>= resultOr (fail . show) pure . parseSchema
  
  getApps :: FileUrl -> IO (App e IO)
  getApps _ = do
    schemaDeities <- getSchema "test/named-resolvers/deities.gql"
    schemaRealms <- getSchema "test/named-resolvers/realms.gql"
    schemaEntities <- getSchema "test/named-resolvers/entities.gql"
    pure
      $ mkApp schemaDeities resolverDeities
      <> mkApp schemaRealms resolverRealms
      <> mkApp schemaEntities resolverEntities
  
  runNamedResolversTest :: FileUrl -> FileUrl -> TestTree
  runNamedResolversTest url = testApi api
    where
      api :: GQLRequest -> IO GQLResponse
      api req = getApps url >>= (`runApp` req)
  