content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module APIConstraints
    ( runAPIConstraints,
    )
  where
  
  import Data.Aeson (Value (..))
  import qualified Data.ByteString.Lazy.Char8 as LBS
  import Data.Morpheus.App
    ( APIConstraint,
      App,
      mkApp,
      runApp,
      withConstraint,
    )
  import Data.Morpheus.App.Internal.Resolving (resultOr)
  import Data.Morpheus.App.NamedResolvers
    ( RootResolverValue,
      object,
      queryResolvers,
    )
  import Data.Morpheus.Core
    ( parseSchema,
    )
  import Data.Morpheus.Types.IO
    ( GQLRequest,
      GQLResponse,
    )
  import Data.Morpheus.Types.Internal.AST
    ( Schema,
      VALID,
    )
  import Data.Morpheus.Types.SelectionTree
    ( SelectionTree (..),
    )
  import Relude hiding (ByteString)
  import Test.Morpheus
    ( FileUrl,
      testApi,
    )
  import Test.Tasty
    ( TestTree,
    )
  
  resolvers :: (Monad m) => RootResolverValue e m
  resolvers =
    queryResolvers
      [ ( "Query",
          traverse
            ( const
                $ object
                  [ ("success", pure "success"),
                    ("forbidden", pure "forbidden!"),
                    ("limited", pure "num <= 5")
                  ]
            )
        )
      ]
  
  getSchema :: String -> IO (Schema VALID)
  getSchema url = LBS.readFile url >>= resultOr (fail . show) pure . parseSchema
  
  getApp :: FileUrl -> IO (App e IO)
  getApp _ = (`mkApp` resolvers) <$> getSchema "test/api-constraints/schema.gql"
  
  forbidden :: APIConstraint
  forbidden _ query
    | hasChild ("forbidden" :: String) query = Left "no forbidden field!"
    | otherwise = Right ()
  
  max5 :: APIConstraint
  max5 _ query =
    case getChild ("limited" :: Text) query >>= getArgument ("num" :: Text) of
      Just (Number n) | n > 5 -> Left ("num " <> show n <> " is greater then 5! but found ")
      _ -> pure ()
  
  runAPIConstraints :: FileUrl -> FileUrl -> TestTree
  runAPIConstraints url = testApi api
    where
      api :: GQLRequest -> IO GQLResponse
      api req = do
        app <- withConstraint max5 . withConstraint forbidden <$> getApp url
        runApp app req
  