content: {-# LANGUAGE TemplateHaskell #-}
  
  -- 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.Aws.Sns
    ( Event,
      EventType (..),
      DeliveryFailure (..),
      evType,
      evEndpoint,
    )
  where
  
  import Amazonka.Data (ToText (..), fromText)
  import Control.Error
  import Control.Lens
  import Data.Aeson
  import Data.Aeson.Lens
  import Gundeck.Aws.Arn (EndpointArn)
  import Imports
  
  data EventType
    = EndpointCreated
    | EndpointUpdated
    | EndpointDeleted
    | DeliveryFailure !DeliveryFailure
    | UnknownEvent !Text
    deriving (Eq, Show)
  
  data DeliveryFailure
    = DeliveryInvalidToken
    | DeliveryFailedPerm
    | DeliveryEndpointDisabled
    | DeliveryTTLExpired
    | DeliveryUnknownFailure !Text
    deriving (Eq, Show)
  
  data Event = Event
    { _evType :: !EventType,
      _evEndpoint :: !EndpointArn
    }
    deriving (Show)
  
  makeLenses ''Event
  
  readDeliveryFailure :: Text -> DeliveryFailure
  readDeliveryFailure "InvalidPlatformToken" = DeliveryInvalidToken
  readDeliveryFailure "DeliveryFailedPerm" = DeliveryFailedPerm
  readDeliveryFailure "EndpointDisabled" = DeliveryEndpointDisabled
  readDeliveryFailure "NotificationTTLExpired" = DeliveryTTLExpired
  readDeliveryFailure other = DeliveryUnknownFailure other
  
  instance ToText DeliveryFailure where
    toText DeliveryInvalidToken = "InvalidPlatformToken"
    toText DeliveryFailedPerm = "DeliveryFailedPerm"
    toText DeliveryEndpointDisabled = "EndpointDisabled"
    toText DeliveryTTLExpired = "NotificationTTLExpired"
    toText (DeliveryUnknownFailure other) = "UnknownFailure: " <> other
  
  readEventType :: Text -> Maybe Text -> EventType
  readEventType "EndpointCreated" _ = EndpointCreated
  readEventType "EndpointUpdated" _ = EndpointUpdated
  readEventType "EndpointDeleted" _ = EndpointDeleted
  readEventType "DeliveryFailure" (Just e) = DeliveryFailure (readDeliveryFailure e)
  readEventType other _ = UnknownEvent other
  
  instance ToText EventType where
    toText EndpointCreated = "EndpointCreated"
    toText EndpointUpdated = "EndpointUpdated"
    toText EndpointDeleted = "EndpointDeleted"
    toText (DeliveryFailure e) = "DeliveryFailure: " <> toText e
    toText (UnknownEvent other) = "UnknownEvent: " <> other
  
  instance FromJSON Event where
    -- n.b. The SNS topic publishing these events must be configured for raw
    -- message delivery: cf. https://aws.amazon.com/sns/faqs/#raw-message-delivery
    parseJSON m = maybe (fail "Failed to parse SNS event") pure $ do
      e <- m ^? key "EndpointArn" . _String >>= hush . fromText
      t <- m ^? key "EventType" . _String
      let f = m ^? key "FailureType" . _String
      pure $! Event (readEventType t f) e
  