{-# LANGUAGE DeriveDataTypeable #-}

-- 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 Brig.API.Types
  ( module Brig.API.Types,
    Activation (..),
    ActivationError (..),
    ClientDataError (..),
    AuthError (..),
    ReAuthError (..),
    LegalHoldLoginError (..),
    RetryAfter (..),
    ListUsersById (..),
  )
where

import Brig.Data.Activation (ActivationError (..))
import Data.Code
import Data.Id
import Data.Qualified
import Data.RetryAfter
import Imports
import Network.Wai.Utilities.Error qualified as Wai
import Wire.API.Federation.Error
import Wire.API.User
import Wire.API.User.Activation
import Wire.AuthenticationSubsystem.Error
import Wire.ClientSubsystem.Error
import Wire.UserKeyStore

-------------------------------------------------------------------------------
-- Successes

data CreateUserResult = CreateUserResult
  { -- | The newly created user account.
    createdAccount :: !User,
    -- | Activation data for the registered email address, if any.
    createdEmailActivation :: !(Maybe Activation),
    -- | Info of a team just created/joined
    createdUserTeam :: !(Maybe CreateUserTeam)
  }
  deriving (Show)

data ActivationResult
  = -- | The key/code was valid and successfully activated.
    ActivationSuccess !(Maybe UserIdentity) !Bool
  | -- | The key/code was valid but already recently activated.
    ActivationPass
  deriving (Show)

-------------------------------------------------------------------------------
-- Failures

data CreateUserError
  = InvalidInvitationCode
  | MissingIdentity
  | EmailActivationError ActivationError
  | PhoneActivationError ActivationError
  | InvalidEmail EmailAddress String
  | InvalidPhone Phone
  | DuplicateUserKey EmailKey
  | BlacklistedUserKey EmailKey
  | TooManyTeamMembers
  | UserCreationRestricted
  | -- | Some precondition on another Wire service failed. We propagate this error.
    ExternalPreconditionFailed Wai.Error

data InvitationError
  = InviteeEmailExists UserId
  | InviteInvalidEmail EmailAddress
  | InviteBlacklistedEmail EmailAddress

data ConnectionError
  = -- | Max. # of 'Accepted' / 'Sent' connections reached
    -- when attempting to create or accept a connection.
    TooManyConnections UserId
  | -- | An invalid connection status change.
    InvalidTransition UserId
  | -- | The target user in an connection attempt is invalid, e.g. not activated.
    InvalidUser (Qualified UserId)
  | -- | An attempt at updating a non-existent connection.
    NotConnected UserId (Qualified UserId)
  | -- | An attempt at creating a connection from an account with
    -- no verified user identity.
    ConnectNoIdentity
  | -- | An attempt at creating an invitation to a blacklisted user key.
    ConnectBlacklistedUserKey EmailKey
  | -- | An attempt at creating an invitation to an invalid email address.
    ConnectInvalidEmail EmailAddress String
  | -- | An attempt at creating an invitation to an invalid phone nbumber.
    ConnectInvalidPhone Phone
  | -- | An attempt at creating a connection with another user from the same binding team.
    ConnectSameBindingTeamUsers
  | -- | Something doesn't work because somebody has a LH device and somebody else has not granted consent.
    ConnectMissingLegalholdConsent
  | -- | Same as above, but because old clients that don't support LH are still in the game.
    ConnectMissingLegalholdConsentOldClients
  | -- | Remote connection creation or update failed because of a federation error
    ConnectFederationError FederationError
  | -- | The teams of the users that want to connect do not federate
    ConnectTeamFederationError

data PasswordResetError
  = PasswordResetInProgress (Maybe Timeout)
  | InvalidPasswordResetKey
  | InvalidPasswordResetCode
  | ResetPasswordMustDiffer

data LegalHoldLoginError
  = LegalHoldLoginNoBindingTeam
  | LegalHoldLoginLegalHoldNotEnabled
  | LegalHoldLoginError LoginError
  | LegalHoldReAuthError ReAuthError

data LoginError
  = LoginFailed
  | LoginSuspended
  | LoginEphemeral
  | LoginPendingActivation
  | LoginThrottled RetryAfter
  | LoginBlocked RetryAfter
  | LoginCodeRequired
  | LoginCodeInvalid
  | LoginPasswordUpdateRequired

data SendActivationCodeError
  = InvalidRecipient EmailKey
  | UserKeyInUse EmailKey
  | ActivationBlacklistedUserKey EmailKey

data DeleteUserError
  = DeleteUserInvalid
  | DeleteUserInvalidCode
  | DeleteUserInvalidPassword
  | DeleteUserMissingPassword
  | DeleteUserPendingCode Timeout
  | DeleteUserOwnerDeletingSelf
  | DeleteUserVerificationCodeThrottled RetryAfter

data AccountStatusError
  = InvalidAccountStatus
  | AccountNotFound

data VerificationCodeThrottledError
  = VerificationCodeThrottled RetryAfter

-------------------------------------------------------------------------------
-- Exceptions

-- | A user name was unexpectedly not found for an existing user ID.
newtype UserDisplayNameNotFound = UserDisplayNameNotFound UserId
  deriving (Typeable)

instance Exception UserDisplayNameNotFound

instance Show UserDisplayNameNotFound where
  show (UserDisplayNameNotFound uid) = "User name not found for user: " ++ show uid

newtype UserProfileNotFound = UserProfileNotFound UserId
  deriving (Typeable)

instance Exception UserProfileNotFound

instance Show UserProfileNotFound where
  show (UserProfileNotFound uid) = "User profile not found for user: " ++ show uid
