-- 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 Gundeck.Notification
  ( paginate,
    PaginateResult (..),
  )
where

import Bilge.RPC
import Bilge.Request
import Bilge.Response
import Control.Lens (view)
import Control.Monad.Catch
import Data.ByteString.Conversion
import Data.Id
import Data.Range
import Data.UUID qualified as UUID
import Gundeck.Monad
import Gundeck.Notification.Data qualified as Data
import Gundeck.Options (brig)
import Imports hiding (getLast)
import Network.HTTP.Types (status400)
import Network.HTTP.Types.Method
import Network.Wai.Utilities.Error
import System.Logger.Class
import System.Logger.Class qualified as Log
import Util.Options (Endpoint (Endpoint))
import Wire.API.Internal.Notification
import Wire.API.Notification

data PaginateResult = PaginateResult
  { paginateResultGap :: Bool,
    paginateResultPage :: QueuedNotificationList
  }

paginate :: UserId -> Maybe NotificationId -> Maybe ClientId -> Range 100 10000 Int32 -> Gundeck PaginateResult
paginate uid since mclt size = do
  traverse_ validateNotificationId since
  for_ mclt $ \clt -> updateActivity uid clt

  time <- posixTime
  rs <- Data.fetch uid mclt since size
  pure $ PaginateResult (Data.resultGap rs) (resultList time rs)
  where
    resultList time rs =
      queuedNotificationList
        (toList (Data.resultSeq rs))
        (Data.resultHasMore rs)
        (Just (msToUTCSecs time))

    validateNotificationId :: NotificationId -> Gundeck ()
    validateNotificationId n =
      unless (isValidNotificationId n) $
        throwM (mkError status400 "bad-request" "Invalid Notification ID")

-- | Update last_active property of the given client by making a request to brig.
updateActivity :: UserId -> ClientId -> Gundeck ()
updateActivity uid clt = do
  r <- do
    Endpoint h p <- view $ options . brig
    rpc "brig" $
      method POST
        . host (toByteString' h)
        . port p
        . paths ["i", "clients", toByteString' uid, toByteString' clt, "activity"]
  when (statusCode r /= 200) $ do
    Log.warn $
      Log.msg ("Could not update client activity" :: ByteString)
        ~~ "user"
        .= UUID.toASCIIBytes (toUUID uid)
        ~~ "client"
        .= clientToText clt
