content: -- 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 Wire.API.Routes.Public.Galley.Feature where
  
  import Data.Id
  import GHC.TypeLits
  import Servant
  import Servant.OpenApi.Internal.Orphans ()
  import Wire.API.Error
  import Wire.API.Error.Galley
  import Wire.API.OAuth
  import Wire.API.Routes.Features
  import Wire.API.Routes.MultiVerb
  import Wire.API.Routes.Named
  import Wire.API.Routes.Public
  import Wire.API.Routes.Version
  import Wire.API.Team.Feature
  import Wire.API.Team.SearchVisibility (TeamSearchVisibilityView)
  
  type FeatureAPIGetPut cfg =
    FeatureAPIGet cfg :<|> FeatureAPIPut cfg
  
  type FeatureAPI =
    FeatureAPIGet SSOConfig
      :<|> FeatureAPIGetPut LegalholdConfig
      :<|> FeatureAPIGetPut SearchVisibilityAvailableConfig
      :<|> SearchVisibilityGet
      :<|> SearchVisibilitySet
      :<|> FeatureAPIGet ValidateSAMLEmailsConfig
      :<|> FeatureAPIGet DigitalSignaturesConfig
      :<|> FeatureAPIGetPut AppLockConfig
      :<|> FeatureAPIGetPut FileSharingConfig
      :<|> FeatureAPIGet ClassifiedDomainsConfig
      :<|> FeatureAPIGetPut ConferenceCallingConfig
      :<|> FeatureAPIGetPut SelfDeletingMessagesConfig
      :<|> FeatureAPIGetPut GuestLinksConfig
      :<|> FeatureAPIGetPut SndFactorPasswordChallengeConfig
      :<|> From 'V5 ::> FeatureAPIGetPut MLSConfig
      :<|> FeatureAPIGetPut ExposeInvitationURLsToTeamAdminConfig
      :<|> FeatureAPIGetPut SearchVisibilityInboundConfig
      :<|> FeatureAPIGetPut OutlookCalIntegrationConfig
      :<|> From 'V5 ::> FeatureAPIGet MlsE2EIdConfig
      :<|> From 'V5 ::> Until 'V6 ::> Named "put-MlsE2EIdConfig@v5" (ZUser :> FeatureStatusBasePutPublic MlsE2EIdConfig)
      :<|> From 'V6 ::> FeatureAPIPut MlsE2EIdConfig
      :<|> From 'V5 ::> FeatureAPIGetPut MlsMigrationConfig
      :<|> From 'V5 ::> FeatureAPIGetPut EnforceFileDownloadLocationConfig
      :<|> From 'V5 ::> FeatureAPIGet LimitedEventFanoutConfig
      :<|> AllTeamFeaturesUserGet
      :<|> AllTeamFeaturesTeamGet
      :<|> DeprecatedFeatureAPI
      :<|> AllDeprecatedFeatureConfigAPI DeprecatedFeatureConfigs
      :<|> FeatureAPIGet DomainRegistrationConfig
      :<|> FeatureAPIGetPut ChannelsConfig
      :<|> FeatureAPIGetPut CellsConfig
      :<|> FeatureAPIGet AllowedGlobalOperationsConfig
      :<|> FeatureAPIGet AssetAuditLogConfig
      :<|> FeatureAPIGet ConsumableNotificationsConfig
      :<|> FeatureAPIGet ChatBubblesConfig
      :<|> FeatureAPIGet AppsConfig
      :<|> FeatureAPIGet SimplifiedUserConnectionRequestQRCodeConfig
      :<|> FeatureAPIGet StealthUsersConfig
  
  type DeprecationNotice1 = "This endpoint is potentially used by the old Android client. It is not used by iOS, team management, or webapp as of June 2022"
  
  type DeprecationNotice2 = "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022"
  
  type DeprecatedFeatureConfigs =
    [ LegalholdConfig,
      SSOConfig,
      SearchVisibilityAvailableConfig,
      ValidateSAMLEmailsConfig,
      DigitalSignaturesConfig,
      AppLockConfig,
      FileSharingConfig,
      ClassifiedDomainsConfig,
      ConferenceCallingConfig,
      SelfDeletingMessagesConfig,
      GuestLinksConfig,
      SndFactorPasswordChallengeConfig,
      MLSConfig
    ]
  
  type family AllDeprecatedFeatureConfigAPI cfgs where
    AllDeprecatedFeatureConfigAPI '[cfg] = FeatureConfigDeprecatedGet DeprecationNotice2 cfg
    AllDeprecatedFeatureConfigAPI (cfg : cfgs) =
      FeatureConfigDeprecatedGet DeprecationNotice2 cfg
        :<|> AllDeprecatedFeatureConfigAPI cfgs
  
  type DeprecatedFeatureAPI =
    FeatureStatusDeprecatedGet DeprecationNotice1 SearchVisibilityAvailableConfig V2
      :<|> FeatureStatusDeprecatedPut DeprecationNotice1 SearchVisibilityAvailableConfig V2
      :<|> FeatureStatusDeprecatedGet DeprecationNotice1 ValidateSAMLEmailsConfig V2
      :<|> FeatureStatusDeprecatedGet DeprecationNotice2 DigitalSignaturesConfig V2
  
  type FeatureAPIGet cfg =
    Named
      '("get", cfg)
      ( Description (FeatureAPIDesc cfg)
          :> (ZUser :> FeatureStatusBaseGet cfg)
      )
  
  type FeatureAPIPut cfg =
    Named
      '("put", cfg)
      ( Description (FeatureAPIDesc cfg)
          :> ZUser
          :> FeatureStatusBasePutPublic cfg
      )
  
  type FeatureStatusDeprecatedGet d feature untilVersion =
    Named
      '("get-deprecated", '(feature, untilVersion))
      (ZUser :> FeatureStatusBaseDeprecatedGet d feature untilVersion)
  
  type FeatureStatusDeprecatedPut d feature untilVersion =
    Named
      '("put-deprecated", '(feature, untilVersion))
      (ZUser :> FeatureStatusBaseDeprecatedPut d feature untilVersion)
  
  type FeatureStatusBaseGet featureConfig =
    Summary (AppendSymbol "Get config for " (FeatureSymbol featureConfig))
      :> CanThrow OperationDenied
      :> CanThrow 'NotATeamMember
      :> CanThrow 'TeamNotFound
      :> "teams"
      :> Capture "tid" TeamId
      :> "features"
      :> FeatureSymbol featureConfig
      :> Get '[Servant.JSON] (LockableFeature featureConfig)
  
  type FeatureStatusBasePutPublic featureConfig =
    Summary (AppendSymbol "Put config for " (FeatureSymbol featureConfig))
      :> CanThrow OperationDenied
      :> CanThrow 'NotATeamMember
      :> CanThrow 'TeamNotFound
      :> CanThrow TeamFeatureError
      :> CanThrowMany (FeatureErrors featureConfig)
      :> "teams"
      :> Capture "tid" TeamId
      :> "features"
      :> FeatureSymbol featureConfig
      :> ReqBody '[Servant.JSON] (Feature featureConfig)
      :> Put '[Servant.JSON] (LockableFeature featureConfig)
  
  -- | A type for a GET endpoint for a feature with a deprecated path
  type FeatureStatusBaseDeprecatedGet desc featureConfig untilVersion =
    ( Summary
        (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig))
        :> Until untilVersion
        :> Description
             ( "Deprecated. Please use `GET /teams/:tid/features/"
                 `AppendSymbol` FeatureSymbol featureConfig
                 `AppendSymbol` "` instead.\n"
                 `AppendSymbol` desc
             )
        :> CanThrow 'NotATeamMember
        :> CanThrow OperationDenied
        :> CanThrow 'TeamNotFound
        :> "teams"
        :> Capture "tid" TeamId
        :> "features"
        :> DeprecatedFeatureName untilVersion featureConfig
        :> Get '[Servant.JSON] (LockableFeature featureConfig)
    )
  
  -- | A type for a PUT endpoint for a feature with a deprecated path
  type FeatureStatusBaseDeprecatedPut desc featureConfig untilVersion =
    Summary
      (AppendSymbol "[deprecated] Get config for " (FeatureSymbol featureConfig))
      :> Until untilVersion
      :> Description
           ( "Deprecated. Please use `PUT /teams/:tid/features/"
               `AppendSymbol` FeatureSymbol featureConfig
               `AppendSymbol` "` instead.\n"
               `AppendSymbol` desc
           )
      :> CanThrow 'NotATeamMember
      :> CanThrow OperationDenied
      :> CanThrow 'TeamNotFound
      :> CanThrow TeamFeatureError
      :> "teams"
      :> Capture "tid" TeamId
      :> "features"
      :> DeprecatedFeatureName untilVersion featureConfig
      :> ReqBody '[Servant.JSON] (Feature featureConfig)
      :> Put '[Servant.JSON] (LockableFeature featureConfig)
  
  type FeatureConfigDeprecatedGet desc featureConfig =
    Named
      '("get-config", featureConfig)
      ( Summary (AppendSymbol "[deprecated] Get feature config for feature " (FeatureSymbol featureConfig))
          :> Until 'V2
          :> Description ("Deprecated. Please use `GET /feature-configs` instead.\n" `AppendSymbol` desc)
          :> ZUser
          :> CanThrow 'NotATeamMember
          :> CanThrow OperationDenied
          :> CanThrow 'TeamNotFound
          :> "feature-configs"
          :> FeatureSymbol featureConfig
          :> Get '[Servant.JSON] (LockableFeature featureConfig)
      )
  
  type AllTeamFeaturesUserGet =
    Named
      "get-all-feature-configs-for-user"
      ( Summary
          "Gets feature configs for a user"
          :> Description
               "Gets feature configs for a user. If the user is a member of a team and has the required permissions, this will return the team's feature configs.\
               \If the user is not a member of a team, this will return the personal feature configs (the server defaults)."
          :> DescriptionOAuthScope 'ReadFeatureConfigs
          :> ZUser
          :> CanThrow 'NotATeamMember
          :> CanThrow OperationDenied
          :> CanThrow 'TeamNotFound
          :> "feature-configs"
          :> Get '[Servant.JSON] AllTeamFeatures
      )
  
  type AllTeamFeaturesTeamGet =
    Named
      "get-all-feature-configs-for-team"
      ( Summary "Gets feature configs for a team"
          :> Description "Gets feature configs for a team. User must be a member of the team and have permission to view team features."
          :> CanThrow 'NotATeamMember
          :> CanThrow OperationDenied
          :> CanThrow 'TeamNotFound
          :> ZLocalUser
          :> "teams"
          :> Capture "tid" TeamId
          :> "features"
          :> Get '[JSON] AllTeamFeatures
      )
  
  type SearchVisibilityGet =
    Named
      "get-search-visibility"
      ( Summary "Shows the value for search visibility"
          :> CanThrow 'NotATeamMember
          :> CanThrow OperationDenied
          :> ZLocalUser
          :> "teams"
          :> Capture "tid" TeamId
          :> "search-visibility"
          :> Get '[JSON] TeamSearchVisibilityView
      )
  
  type SearchVisibilitySet =
    Named
      "set-search-visibility"
      ( Summary "Sets the search visibility for the whole team"
          :> CanThrow 'NotATeamMember
          :> CanThrow OperationDenied
          :> CanThrow 'TeamSearchVisibilityNotEnabled
          :> CanThrow 'TeamNotFound
          :> CanThrow TeamFeatureError
          :> ZLocalUser
          :> "teams"
          :> Capture "tid" TeamId
          :> "search-visibility"
          :> ReqBody '[JSON] TeamSearchVisibilityView
          :> MultiVerb 'PUT '[JSON] '[RespondEmpty 204 "Search visibility set"] ()
      )
  