content: -- Disabling to stop warnings on HasCallStack
  {-# OPTIONS_GHC -Wno-redundant-constraints #-}
  
  -- This file is part of the Wire Server implementation.
  --
  -- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
  --
  -- This program is free software: you can redistribute it and/or modify it under
  -- the terms of the GNU Affero General Public License as published by the Free
  -- Software Foundation, either version 3 of the License, or (at your option) any
  -- later version.
  --
  -- This program is distributed in the hope that it will be useful, but WITHOUT
  -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  -- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  -- details.
  --
  -- You should have received a copy of the GNU Affero General Public License along
  -- with this program. If not, see <https://www.gnu.org/licenses/>.
  
  module API.Internal
    ( tests,
    )
  where
  
  import Bilge
  import Bilge.Assert
  import Brig.Data.User
  import Brig.Options qualified as Opt
  import Cassandra qualified as C
  import Cassandra qualified as Cass
  import Cassandra.Util
  import Control.Monad.Catch
  import Data.ByteString.Conversion (toByteString')
  import Data.Id
  import Data.Qualified
  import Imports
  import Test.Tasty
  import Test.Tasty.HUnit
  import Util
  import Util.Options (Endpoint)
  import Wire.API.User
  
  type TestConstraints m = (MonadFail m, MonadCatch m, MonadIO m, MonadHttp m)
  
  tests :: Opt.Opts -> Manager -> Cass.ClientState -> Brig -> Endpoint -> Gundeck -> Galley -> IO TestTree
  tests opts mgr db brig brigep _gundeck galley = do
    pure $
      testGroup "api/internal" $
        [ test mgr "suspend and unsuspend user" $ testSuspendUser db brig,
          test mgr "suspend non existing user and verify no db entry" $
            testSuspendNonExistingUser db brig,
          test mgr "writetimeToInt64" $ testWritetimeRepresentation opts mgr db brig brigep galley
        ]
  
  testSuspendUser :: forall m. (TestConstraints m) => Cass.ClientState -> Brig -> m ()
  testSuspendUser db brig = do
    user <- randomUser brig
    let checkAccountStatus s = do
          mbStatus <- Cass.runClient db (lookupStatus (userId user))
          liftIO $ mbStatus @?= Just s
  
    setAccountStatus brig (userId user) Suspended !!! const 200 === statusCode
    checkAccountStatus Suspended
    setAccountStatus brig (userId user) Active !!! const 200 === statusCode
    checkAccountStatus Active
  
  testSuspendNonExistingUser :: forall m. (TestConstraints m) => Cass.ClientState -> Brig -> m ()
  testSuspendNonExistingUser db brig = do
    nonExistingUserId <- randomId
    setAccountStatus brig nonExistingUserId Suspended !!! const 404 === statusCode
    isUserCreated <- Cass.runClient db (userExists nonExistingUserId)
    liftIO $ isUserCreated @?= False
  
  setAccountStatus :: (MonadHttp m, HasCallStack) => Brig -> UserId -> AccountStatus -> m ResponseLBS
  setAccountStatus brig u s =
    put
      ( brig
          . paths ["i", "users", toByteString' u, "status"]
          . contentJson
          . json (AccountStatusUpdate s)
      )
  
  testWritetimeRepresentation :: forall m. (TestConstraints m) => Opt.Opts -> Manager -> Cass.ClientState -> Brig -> Endpoint -> Galley -> m ()
  testWritetimeRepresentation _ _mgr db brig _brigep _galley = do
    quid <- userQualifiedId <$> randomUser brig
    let uid = qUnqualified quid
  
    ref <- fromJust <$> (runIdentity <$$> Cass.runClient db (C.query1 q1 (C.params C.LocalQuorum (Identity uid))))
  
    wt <- fromJust <$> (runIdentity <$$> Cass.runClient db (C.query1 q2 (C.params C.LocalQuorum (Identity uid))))
  
    liftIO $ assertEqual "writetimeToInt64(<fromCql WRITETIME(status)>) does not match WRITETIME(status)" ref (writetimeToInt64 wt)
    where
      q1 :: C.PrepQuery C.R (Identity UserId) (Identity Int64)
      q1 = "SELECT WRITETIME(status) from user where id = ?"
  
      q2 :: C.PrepQuery C.R (Identity UserId) (Identity (Writetime ()))
      q2 = "SELECT WRITETIME(status) from user where id = ?"
  
  lookupStatus :: UserId -> C.Client (Maybe AccountStatus)
  lookupStatus u =
    (runIdentity =<<)
      <$> C.retry C.x1 (C.query1 statusSelect (C.params C.LocalQuorum (Identity u)))
    where
      statusSelect :: C.PrepQuery C.R (Identity UserId) (Identity (Maybe AccountStatus))
      statusSelect = "SELECT status FROM user WHERE id = ?"
  