{-# LANGUAGE QuasiQuotes #-}

-- | [Fitbit Authorization developer guide](https://dev.fitbit.com/build/reference/web-api/developer-guide/authorization/)
module Network.OAuth2.Provider.Fitbit where

import Control.Monad (mzero)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.Except (ExceptT (..))
import Data.Aeson
import Data.ByteString.Lazy.Char8 qualified as BSL
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Text.Lazy (Text)
import Network.HTTP.Conduit (Manager)
import Network.OAuth.OAuth2
import Network.OAuth2.Experiment
import Network.OAuth2.Provider
import URI.ByteString.QQ

sampleFitbitAuthorizationCodeApp :: AuthorizationCodeApplication
sampleFitbitAuthorizationCodeApp :: AuthorizationCodeApplication
sampleFitbitAuthorizationCodeApp =
  AuthorizationCodeApplication
    { acClientId :: ClientId
acClientId = ClientId
""
    , acClientSecret :: ClientSecret
acClientSecret = ClientSecret
""
    , acScope :: Set Scope
acScope = Set Scope
forall a. Set a
Set.empty
    , acAuthorizeRequestExtraParams :: Map Text Text
acAuthorizeRequestExtraParams = Map Text Text
forall k a. Map k a
Map.empty
    , acAuthorizeState :: AuthorizeState
acAuthorizeState = AuthorizeState
"CHANGE_ME"
    , acRedirectUri :: URI
acRedirectUri = [uri|http://localhost|]
    , acName :: Text
acName = Text
"sample-fitbit-authorization-code-app"
    , acTokenRequestAuthenticationMethod :: ClientAuthenticationMethod
acTokenRequestAuthenticationMethod = ClientAuthenticationMethod
ClientSecretBasic
    }

fetchUserInfo ::
  (MonadIO m, HasUserInfoRequest a, FromJSON b) =>
  IdpApplication i a ->
  Manager ->
  AccessToken ->
  ExceptT BSL.ByteString m b
fetchUserInfo :: forall {k} (m :: * -> *) a b (i :: k).
(MonadIO m, HasUserInfoRequest a, FromJSON b) =>
IdpApplication i a
-> Manager -> AccessToken -> ExceptT ByteString m b
fetchUserInfo = IdpApplication i a
-> Manager -> AccessToken -> ExceptT ByteString m b
forall {k} (m :: * -> *) a b (i :: k).
(MonadIO m, HasUserInfoRequest a, FromJSON b) =>
IdpApplication i a
-> Manager -> AccessToken -> ExceptT ByteString m b
conduitUserInfoRequest

defaultFitbitIdp :: Idp Fitbit
defaultFitbitIdp :: Idp 'Fitbit
defaultFitbitIdp =
  Idp
    { idpUserInfoEndpoint :: URI
idpUserInfoEndpoint = [uri|https://api.fitbit.com/1/user/-/profile.json|]
    , idpAuthorizeEndpoint :: URI
idpAuthorizeEndpoint = [uri|https://www.fitbit.com/oauth2/authorize|]
    , idpTokenEndpoint :: URI
idpTokenEndpoint = [uri|https://api.fitbit.com/oauth2/token|]
    , idpDeviceAuthorizationEndpoint :: Maybe URI
idpDeviceAuthorizationEndpoint = Maybe URI
forall a. Maybe a
Nothing
    }

data FitbitUser = FitbitUser
  { FitbitUser -> Text
userId :: Text
  , FitbitUser -> Text
userName :: Text
  , FitbitUser -> Int
userAge :: Int
  }
  deriving (Int -> FitbitUser -> ShowS
[FitbitUser] -> ShowS
FitbitUser -> String
(Int -> FitbitUser -> ShowS)
-> (FitbitUser -> String)
-> ([FitbitUser] -> ShowS)
-> Show FitbitUser
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FitbitUser -> ShowS
showsPrec :: Int -> FitbitUser -> ShowS
$cshow :: FitbitUser -> String
show :: FitbitUser -> String
$cshowList :: [FitbitUser] -> ShowS
showList :: [FitbitUser] -> ShowS
Show, FitbitUser -> FitbitUser -> Bool
(FitbitUser -> FitbitUser -> Bool)
-> (FitbitUser -> FitbitUser -> Bool) -> Eq FitbitUser
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FitbitUser -> FitbitUser -> Bool
== :: FitbitUser -> FitbitUser -> Bool
$c/= :: FitbitUser -> FitbitUser -> Bool
/= :: FitbitUser -> FitbitUser -> Bool
Eq)

instance FromJSON FitbitUser where
  parseJSON :: Value -> Parser FitbitUser
parseJSON (Object Object
o) =
    Text -> Text -> Int -> FitbitUser
FitbitUser
      (Text -> Text -> Int -> FitbitUser)
-> Parser Text -> Parser (Text -> Int -> FitbitUser)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Object
o Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user") Parser Object -> (Object -> Parser Text) -> Parser Text
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"encodedId"))
      Parser (Text -> Int -> FitbitUser)
-> Parser Text -> Parser (Int -> FitbitUser)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ((Object
o Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user") Parser Object -> (Object -> Parser Text) -> Parser Text
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"fullName"))
      Parser (Int -> FitbitUser) -> Parser Int -> Parser FitbitUser
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ((Object
o Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"user") Parser Object -> (Object -> Parser Int) -> Parser Int
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Key -> Parser Int
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"age"))
  parseJSON Value
_ = Parser FitbitUser
forall a. Parser a
forall (m :: * -> *) a. MonadPlus m => m a
mzero