
module Test.Server.ReverseProxy where

import Control.Monad (void)
import Data.Function ((&))
import Gargantext.MicroServices.ReverseProxy
import Network.HTTP.Client
import Network.HTTP.Types.Status
import Prelude
import Servant.Auth.Client (Token(..))
import Servant.Client.Streaming
import Servant.Client.Generic (genericClient)
import Test.API.Setup (setupEnvironment, withBackendServerAndProxy, createAliceAndBob)
import Test.Hspec
import Gargantext.Core.Types.Individu (GargPassword(..))
import Gargantext.API.Admin.Auth.Types
import Test.API.Authentication (auth_api)
import Control.Lens ((^.))
import Test.API.Routes (toServantToken)


reverseProxyClient :: ReverseProxyAPI (AsClientT ClientM)
reverseProxyClient = genericClient

tests :: Spec
tests = describe "Microservices proxy" $ do
  writeFrameTests

writeFrameTests :: Spec
writeFrameTests = sequential $ aroundAll withBackendServerAndProxy $ beforeAllWith (\ctx@(testEnv, _, _) -> setupEnvironment testEnv >>= (const $ pure ctx)) $ do
  describe "Write Frame Reverse Proxy" $ do
    it "should disallow unauthenticated requests" $ \(_testEnv, _serverPort, proxyPort) -> do
      baseUrl <- parseBaseUrl "http://localhost"
      manager <- newManager defaultManagerSettings
      let clientEnv prt = mkClientEnv manager (baseUrl { baseUrlPort = prt })
      result <- runClientM (reverseProxyClient & notesServiceProxy
                                               & ($ (Token "bogus"))
                                               & notesEp
                                               & ($ (FrameId "abcdef"))
                                               & ($ Nothing)
                                               & ($ "GET")
                           ) (clientEnv proxyPort)

      case result of
        Right response
          -> responseStatusCode response `shouldBe` status401
        Left (FailureResponse _ response)
          -> responseStatusCode response `shouldBe` status401
        Left err
          -> fail (show err)

    it "should allow authenticated requests" $ \(testEnv, serverPort, proxyPort) -> do
      -- Let's create the Alice user.
      void $ createAliceAndBob testEnv
      baseUrl <- parseBaseUrl "http://localhost"
      manager <- newManager defaultManagerSettings
      let clientEnv prt = mkClientEnv manager (baseUrl { baseUrlPort = prt })

      let authPayload = AuthRequest "alice@gargan.text" (GargPassword "alice")
      result0 <- runClientM (auth_api authPayload) (clientEnv serverPort)

      case result0 of
        Left err -> fail (show err)
        Right autRes -> do
          result <- runClientM (reverseProxyClient & notesServiceProxy
                                                   & ($ (toServantToken $ autRes ^. authRes_token))
                                                   & notesEp
                                                   & ($ (FrameId "abcdef"))
                                                   & ($ Nothing)
                                                   & ($ "GET")
                               ) (clientEnv proxyPort)

          -- The actual request to the reverse proxy might fail (because our
          -- environment is not setup correctly, for example) but crucially here
          -- we want to test that with a valid authentication we don't hit the
          -- 401 error.
          case result of
            Right response
              -> responseStatusCode response `shouldNotBe` status401
            Left (FailureResponse _ response)
              -> responseStatusCode response `shouldNotBe` status401
            Left err
              -> fail (show err)
