{-# LANGUAGE LambdaCase          #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Antiope.Core.Error
  ( handle404ToNone
  , handleServiceError
  ) where

import Control.Monad.Catch       (catch, throwM)
import Network.AWS               (Error (..), MonadAWS, ServiceError (..))
import Network.HTTP.Types.Status (Status (..))

handle404ToNone :: MonadAWS m
  => m a
  -> m (Maybe a)
handle404ToNone f =
  handleServiceError f Just $ \case
    (Status 404 _) -> Just Nothing
    _              -> Nothing

handleServiceError :: MonadAWS m
  => m a                  -- ^ AWS action
  -> (a -> b)             -- ^ Transform successful result
  -> (Status -> Maybe b)  -- ^ Compensate with the failure. 'Nothing' means that the error is not handled
  -> m b                  -- ^ Final result. In case of unhandled errors the exception is re-thrown.
handleServiceError ma success failure =
  (success <$> ma) `catch` \(err :: Error) -> case err of
    (ServiceError (ServiceError' _ status _ _ _ _)) -> maybe (throwM err) pure (failure status)
    _                                               -> throwM err