module Network.CircleCI.CheckoutKey (
    
      getCheckoutKeys
    , getCheckoutKey
    , createCheckoutKey
    , deleteCheckoutKey
    
    , Fingerprint (..)
    , CheckoutKeyInfo (..)
    , CheckoutKeyType (..)
    , CheckoutKeyDeleted (..)
    , module Network.CircleCI.Common.Types
    , module Network.CircleCI.Common.Run
) where
import           Network.CircleCI.Common.URL
import           Network.CircleCI.Common.Types
import           Network.CircleCI.Common.HTTPS
import           Network.CircleCI.Common.Run
import           Control.Monad                  ( mzero )
import           Control.Monad.Except           ( runExceptT )
import           Control.Monad.Reader           ( ask )
import           Control.Monad.IO.Class         ( liftIO )
import           Data.Aeson
import           Data.Aeson.Types
import qualified Data.Proxy                     as P
import           Data.Text                      ( Text )
import           Data.Time.Clock                ( UTCTime )
import           Network.HTTP.Client            ( Manager )
import           Servant.API
import           Servant.Client
getCheckoutKeys :: ProjectPoint                       
                -> CircleCIResponse [CheckoutKeyInfo] 
getCheckoutKeys project = do
    AccountAPIToken token <- ask
    liftIO . runExceptT $ do
        manager <- httpsManager
        servantGetCheckoutKeys (userName project)
                               (projectName project)
                               (Just token)
                               manager
                               apiBaseUrl
getCheckoutKey :: ProjectPoint                      
               -> Fingerprint                       
               -> CircleCIResponse CheckoutKeyInfo  
getCheckoutKey project (Fingerprint aFingerprint) = do
    AccountAPIToken token <- ask
    liftIO . runExceptT $ do
        manager <- httpsManager
        servantGetCheckoutKey (userName project)
                              (projectName project)
                              aFingerprint
                              (Just token)
                              manager
                              apiBaseUrl
createCheckoutKey :: ProjectPoint                     
                  -> CircleCIResponse CheckoutKeyInfo 
createCheckoutKey project = do
    AccountAPIToken token <- ask
    liftIO . runExceptT $ do
        manager <- httpsManager
        servantCreateCheckoutKey (userName project)
                                 (projectName project)
                                 (Just token)
                                 manager
                                 apiBaseUrl
deleteCheckoutKey :: ProjectPoint                         
                  -> Fingerprint                          
                  -> CircleCIResponse CheckoutKeyDeleted  
deleteCheckoutKey project (Fingerprint aFingerprint) = do
    AccountAPIToken token <- ask
    liftIO . runExceptT $ do
        manager <- httpsManager
        servantDeleteCheckoutKey (userName project)
                                 (projectName project)
                                 aFingerprint
                                 (Just token)
                                 manager
                                 apiBaseUrl
newtype Fingerprint = Fingerprint Text
                    deriving (Eq, Show)
data CheckoutKeyType = GitHubDeployKey  
                     | GitHubUserKey    
                     deriving (Eq, Show)
data CheckoutKeyInfo = CheckoutKeyInfo {
      publicKey   :: Text            
    , keyType     :: CheckoutKeyType 
    , fingerprint :: Fingerprint     
    , preferred   :: Bool            
    , issueDate   :: UTCTime         
    } deriving (Eq, Show)
instance FromJSON CheckoutKeyInfo where
    parseJSON (Object o) = CheckoutKeyInfo
        <$>  o .: "public_key"
        <*> (o .: "type"        >>= toCheckoutKeyType)
        <*> (o .: "fingerprint" >>= toFingerprint)
        <*>  o .: "preferred"
        <*>  o .: "time"
    parseJSON _ = mzero
toCheckoutKeyType :: Text -> Parser CheckoutKeyType
toCheckoutKeyType "deploy-key"      = return GitHubDeployKey
toCheckoutKeyType "github-user-key" = return GitHubUserKey
toCheckoutKeyType _                 = return GitHubDeployKey
toFingerprint :: Text -> Parser Fingerprint
toFingerprint = return . Fingerprint
data CheckoutKeyDeleted = KeySuccessfullyDeleted
                        | UnableToDeleteKey ErrorMessage
                        deriving (Show)
instance FromJSON CheckoutKeyDeleted where
    parseJSON (Object o) =
        o .: "message" >>= toCheckoutKeyDeleted
    parseJSON _ = mzero
toCheckoutKeyDeleted :: Text -> Parser CheckoutKeyDeleted
toCheckoutKeyDeleted "ok"       = return KeySuccessfullyDeleted
toCheckoutKeyDeleted rawMessage = return $ UnableToDeleteKey rawMessage
type CheckoutKeyAPI =
         GetCheckoutKeysCall
    :<|> GetCheckoutKeyCall
    :<|> CreateCheckoutKeyCall
    :<|> DeleteCheckoutKeyCall
type GetCheckoutKeysCall =
       "project"
    :> Capture "username" UserName
    :> Capture "project" ProjectName
    :> "checkout-key"
    :> QueryParam "circle-token" Token
    :> Get '[JSON] [CheckoutKeyInfo]
    
type GetCheckoutKeyCall =
       "project"
    :> Capture "username" UserName
    :> Capture "project" ProjectName
    :> "checkout-key"
    :> Capture "fingerprint" Text
    :> QueryParam "circle-token" Token
    :> Get '[JSON] CheckoutKeyInfo
    
type CreateCheckoutKeyCall =
       "project"
    :> Capture "username" UserName
    :> Capture "project" ProjectName
    :> "checkout-key"
    :> QueryParam "circle-token" Token
    :> Post '[JSON] CheckoutKeyInfo
    
type DeleteCheckoutKeyCall =
       "project"
    :> Capture "username" UserName
    :> Capture "project" ProjectName
    :> "checkout-key"
    :> Capture "fingerprint" Text
    :> QueryParam "circle-token" Token
    :> Delete '[JSON] CheckoutKeyDeleted
    
servantGetCheckoutKeys :: UserName
                       -> ProjectName
                       -> Maybe Token
                       -> Manager
                       -> BaseUrl
                       -> ClientM [CheckoutKeyInfo]
servantGetCheckoutKey :: UserName
                      -> ProjectName
                      -> Text
                      -> Maybe Token
                      -> Manager
                      -> BaseUrl
                      -> ClientM CheckoutKeyInfo
servantCreateCheckoutKey :: UserName
                         -> ProjectName
                         -> Maybe Token
                         -> Manager
                         -> BaseUrl
                         -> ClientM CheckoutKeyInfo
servantDeleteCheckoutKey :: UserName
                         -> ProjectName
                         -> Text
                         -> Maybe Token
                         -> Manager
                         -> BaseUrl
                         -> ClientM CheckoutKeyDeleted
servantGetCheckoutKeys
 :<|> servantGetCheckoutKey
 :<|> servantCreateCheckoutKey
 :<|> servantDeleteCheckoutKey = client checkoutKeyAPI
checkoutKeyAPI :: P.Proxy CheckoutKeyAPI
checkoutKeyAPI = P.Proxy