-- 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 Brig.DeleteQueue.Interpreter
  ( runDeleteQueue,
    QueueEnv (..),
  )
where

import Amazonka.SQS.Lens
import Brig.AWS qualified as AWS
import Brig.Queue.Stomp qualified as Stomp
import Control.Exception (ErrorCall (..))
import Control.Lens
import Data.Aeson
import Data.ByteString.Base16 qualified as B16
import Data.ByteString.Lazy qualified as BL
import Data.Text as T hiding (show)
import Data.Text.Encoding qualified as T
import Imports
import OpenSSL.EVP.Digest hiding (digest)
import Polysemy
import Polysemy.Error
import System.Logger.Class qualified as Log
import Wire.DeleteQueue
import Wire.InternalEvent
import Wire.Sem.Logger

-- | The queue environment constructed from `QueueOpts`.
data QueueEnv
  = StompQueueEnv Stomp.Broker Text
  | SqsQueueEnv AWS.Env Int Text

runDeleteQueue ::
  ( Member (Embed IO) r,
    Member (Logger (Log.Msg -> Log.Msg)) r,
    Member (Error ErrorCall) r
  ) =>
  QueueEnv ->
  InterpreterFor DeleteQueue r
runDeleteQueue queueEnv =
  interpret $ \case
    EnqueueUserDeletion userId -> enqueue queueEnv (DeleteUser userId)
    EnqueueClientDeletion clientId userId mConnId -> enqueue queueEnv (DeleteClient clientId userId mConnId)
    EnqueueServiceDeletion providerId serviceId -> enqueue queueEnv (DeleteService providerId serviceId)

-- | Enqueue a message.
--
-- Throws an error in case of failure.
enqueue ::
  ( Member (Embed IO) r,
    Member (Logger (Log.Msg -> Log.Msg)) r,
    Member (Error ErrorCall) r
  ) =>
  (ToJSON a) =>
  QueueEnv ->
  a ->
  Sem r ()
enqueue (StompQueueEnv broker queue) message =
  embed @IO $ Stomp.enqueue broker queue message
enqueue (SqsQueueEnv awsEnv _ queue) message = do
  let body = encode message
  md5 <- embed @IO $ getDigestByName "MD5"
  let bodyMD5 = fmap (flip digest body) md5
  resp <- embed @IO $ AWS.execute awsEnv (AWS.enqueueStandard queue body)
  unless (resp ^. sendMessageResponse_mD5OfMessageBody == bodyMD5) $ do
    err $
      Log.msg (Log.val "Returned hash (MD5) doesn't match message hash")
        . Log.field "SqsQueue" (show queue)
        . Log.field "returned_hash" (show (resp ^. sendMessageResponse_mD5OfMessageBody))
        . Log.field "message_hash" (show (Just bodyMD5))
    throw (ErrorCall "The server couldn't access a queue")
  where
    digest :: Digest -> BL.ByteString -> Text
    digest d = T.decodeLatin1 . B16.encode . digestLBS d
