{-# LANGUAGE RecordWildCards #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2025 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 Test.Wire.Util where

import Data.Default
import Data.Domain (Domain (Domain))
import Data.Misc
import Data.Proxy
import Data.Range
import Data.Secret (secretText)
import Imports
import Network.HTTP.Client hiding (Proxy)
import System.Logger.Class qualified as Logger
import Util.Options (Endpoint (..), PasswordHashingOptions (..))
import Wire.API.Conversation.Config
import Wire.API.Team.FeatureFlags
import Wire.BackgroundWorker.Env hiding (federatorInternal)
import Wire.BackgroundWorker.Env qualified as E
import Wire.BackgroundWorker.Options
import Wire.PostgresMigrationOpts
import Wire.RateLimit.Interpreter (RateLimitConfig (..), TokenBucketConfig (..), newRateLimitEnv)

testEnv :: IO Env
testEnv = do
  http2Manager <- initHttp2Manager
  logger <- Logger.new Logger.defSettings
  let cassandra = undefined
      cassandraGalley = undefined
      cassandraBrig = undefined
      postgresMigration =
        PostgresMigrationOpts
          { conversation = CassandraStorage,
            conversationCodes = CassandraStorage,
            teamFeatures = CassandraStorage,
            domainRegistration = CassandraStorage,
            user = CassandraStorage
          }
  statuses <- newIORef mempty
  backendNotificationMetrics <- mkBackendNotificationMetrics
  meetingsCleanupMetrics <- mkMeetingsCleanupMetrics
  workerRunningGauge <- mkWorkerRunningGauge
  httpManager <- newManager defaultManagerSettings
  let federatorInternal = Endpoint "localhost" 0
      rabbitmqAdminClient = undefined
      rabbitmqVHost = undefined
      defederationTimeout = responseTimeoutNone
      backendNotificationsConfig = BackendNotificationsConfig 1000 500000 1000
      backgroundJobsConfig =
        BackgroundJobsConfig
          { concurrency = toRange (Proxy @1),
            jobTimeout = Duration 100,
            maxAttempts = toRange (Proxy @3)
          }
      hasqlPool = undefined
      amqpJobsPublisherChannel = undefined
      amqpBackendNotificationsChannel = undefined
      federationDomain = Domain "local"
      gundeckEndpoint = undefined
      brigEndpoint = undefined
      sparEndpoint = Endpoint "localhost" 0
      galleyEndpoint = undefined
      maxTeamSize = 1000
      maxFanoutSize = Nothing
      exposeInvitationURLsTeamAllowlist = Nothing
      intraListing = True
      federationProtocols = Nothing
      guestLinkTTLSeconds = Nothing
      passwordHashingOptions = PasswordHashingScrypt
      checkGroupInfo = Nothing
      arbiterConnStr = secretText ""
      convCodeURI = Left (fromRight (error "Failed to parse test HttpsUrl") $ httpsUrlFromText "https://localhost")
      featureFlags = def
      conversationSubsystemConfig =
        ConversationSubsystemConfig
          { mlsKeys = Nothing,
            federationProtocols = Nothing,
            legalholdDefaults = FeatureLegalHoldDisabledPermanently,
            maxConvSize = 500,
            listClientsUsingBrig = False
          }
  passwordHashingRateLimitEnv <- newRateLimitEnv defTestRateLimitConfig
  pure Env {..}

defTestRateLimitConfig :: RateLimitConfig
defTestRateLimitConfig =
  RateLimitConfig
    { ipv4CidrBlock = 32,
      ipv6CidrBlock = 128,
      ipAddressExceptions = [],
      maxRateLimitedKeys = 1000,
      ipAddrLimit = TokenBucketConfig {burst = 100, inverseRate = 1_000_000},
      userLimit = TokenBucketConfig {burst = 100, inverseRate = 1_000_000},
      internalLimit = TokenBucketConfig {burst = 100, inverseRate = 1_000_000}
    }

runTestAppT :: AppT IO a -> Int -> IO a
runTestAppT app port = do
  baseEnv <- testEnv
  runTestAppTWithEnv baseEnv app port

runTestAppTWithEnv :: Env -> AppT IO a -> Int -> IO a
runTestAppTWithEnv Env {..} app port = do
  let env = Env {federatorInternal = Endpoint "localhost" (fromIntegral port), ..}
  runAppT env app
