-- 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 API.Gundeck where

import API.Common
import qualified Data.ByteString.Base16 as Base16
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import Testlib.Prelude

data GetNotifications = GetNotifications
  { since :: Maybe String,
    size :: Maybe Int,
    client :: Maybe String
  }

instance Default GetNotifications where
  def = GetNotifications {since = Nothing, size = Nothing, client = Nothing}

getNotifications ::
  (HasCallStack, MakesValue user) =>
  user ->
  GetNotifications ->
  App Response
getNotifications user r = do
  req <- baseRequest user Gundeck Versioned "/notifications"
  let req' =
        req
          & addQueryParams
            ( [("since", since) | since <- toList r.since]
                <> [("client", c) | c <- toList r.client]
                <> [("size", show size) | size <- toList r.size]
            )
  submit "GET" req'

data GetNotification = GetNotification
  { client :: Maybe String
  }

instance Default GetNotification where
  def = GetNotification Nothing

getNotification ::
  (HasCallStack, MakesValue user, MakesValue nid) =>
  user ->
  GetNotification ->
  nid ->
  App Response
getNotification user opts nid = do
  n <- nid & asString
  req <-
    baseRequest user Gundeck Versioned
      $ joinHttpPath ["notifications", n]
  submit "GET" $ req & addQueryParams [("client", c) | c <- toList opts.client]

getLastNotification ::
  (HasCallStack, MakesValue user) =>
  user ->
  GetNotification ->
  App Response
getLastNotification user opts = do
  req <-
    baseRequest user Gundeck Versioned "/notifications/last"
  submit "GET" $ req & addQueryParams [("client", c) | c <- toList opts.client]

data GeneratePushToken = GeneratePushToken
  { transport :: String,
    app :: String,
    tokenSize :: Int
  }

instance Default GeneratePushToken where
  def =
    GeneratePushToken
      { transport = "GCM",
        app = "test",
        tokenSize = 16
      }

generateAndPostPushToken ::
  (HasCallStack, MakesValue user, MakesValue client) =>
  user ->
  client ->
  GeneratePushToken ->
  App Response
generateAndPostPushToken user client args = do
  token <- generateToken args.tokenSize
  clientId <- make client & asString
  postPushToken user $ PushToken args.transport args.app token clientId

data PushToken = PushToken
  { transport :: String,
    app :: String,
    token :: String,
    client :: String
  }
  deriving (Show, Eq)

instance ToJSON PushToken where
  toJSON pt =
    object
      [ "transport" .= pt.transport,
        "app" .= pt.app,
        "token" .= pt.token,
        "client" .= pt.client
      ]

instance MakesValue PushToken where
  make = pure . toJSON

generateToken :: Int -> App String
generateToken =
  fmap (Text.unpack . Text.decodeUtf8 . Base16.encode) . randomBytes

postPushToken ::
  ( HasCallStack,
    MakesValue token,
    MakesValue user
  ) =>
  user ->
  token ->
  App Response
postPushToken user token = do
  req <- baseRequest user Gundeck Versioned "/push/tokens"
  tokenJson <- make token
  submit "POST" $ req & addJSON tokenJson

listPushTokens :: (MakesValue user) => user -> App Response
listPushTokens user = do
  req <-
    baseRequest user Gundeck Versioned
      $ joinHttpPath ["/push/tokens"]
  submit "GET" req

unregisterClient ::
  (MakesValue user, MakesValue client) =>
  user ->
  client ->
  App Response
unregisterClient user client = do
  cid <- asString client
  req <-
    baseRequest user Gundeck Unversioned
      $ joinHttpPath ["/i/clients", cid]
  submit "DELETE" req

getServerTime ::
  (MakesValue user) =>
  user ->
  App Response
getServerTime user = do
  req <- baseRequest user Gundeck Versioned "/time"
  submit "GET" req
