-- Copyright (c) 2013-2014 PivotCloud, Inc.
--
-- Aws.Lambda.Types
--
-- Please feel free to contact us at licensing@pivotmail.com with any
-- contributions, additions, or other feedback; we would love to hear from
-- you.
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may
-- not use this file except in compliance with the License. You may obtain a
-- copy of the License at http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations
-- under the License.

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UnicodeSyntax #-}

module Aws.Lambda.Types
( -- * Abstract types
  PaginationToken
, LambdaUuid
, ConfigurationId

  -- ** Lenses
, ptText
, cidText
, luText

  -- * Event Source Configuration
, EventSourceConfiguration(..)
, EventSourceParameters(..)
, EventSourceStatus

  -- ** Lenses
, escBatchSize
, escEventSource
, escFunctionName
, escIsActive
, escLastModified
, escParameters
, escRole
, escStatus
, escUuid
, espInitialPositionInStream

  -- ** Prisms
, _EventSourceStatusPending
, _EventSourceStatusOk
, _EventSourceStatusProblem
, _TextEventSourceStatus

  -- * Function Configuration
, FunctionConfiguration(..)
, emptyFunctionConfiguration
, FunctionMode(..)
, FunctionRuntime(..)
, functionModeToText
, functionRuntimeToText

-- ** Lenses
, fcCodeSize
, fcConfigurationId
, fcDescription
, fcFunctionArn
, fcFunctionName
, fcHandler
, fcLastModified
, fcMemorySize
, fcMode
, fcRole
, fcRuntime
, fcTimeout

  -- ** Prisms
, _FunctionModeEvent
, _FunctionRuntimeNodeJs
, _TextFunctionMode
, _TextFunctionRuntime

-- * Misc
, StreamPosition(..)
, _StreamPositionTrimHorizon
, _StreamPositionLatest
, FunctionCodeLocation(..)
, fclLocation
, fclRepositoryType
, Arn
, arnToText
, LambdaDateTime(..)
, _LambdaDateTime
, _TextLambdaDateTime
) where

import Aws.Lambda.Internal.Utils

import Control.Applicative
import Control.Applicative.Unicode
import Control.Lens hiding ((.=))
import Control.Monad.Unicode
import Data.Aeson
import Data.Aeson.Types
import Data.Aeson.Lens
import Data.Monoid
import Data.Monoid.Unicode
import qualified Data.Text as T
import Data.Time
import Prelude.Unicode
import System.Locale

type Arn = T.Text

arnToText
   Arn
   T.Text
arnToText = id

newtype PaginationToken
  = PaginationToken
  { _ptText  T.Text
  } deriving (Eq, Show)

ptText  Getter PaginationToken T.Text
ptText = to _ptText

instance FromJSON PaginationToken where
  parseJSON =
    withText "PaginationToken" $
      pure  PaginationToken

instance ToJSON PaginationToken where
  toJSON = String  _ptText

newtype LambdaUuid
  = LambdaUuid
  { _luText  T.Text
  } deriving (Eq, Show, ToJSON)

luText  Getter LambdaUuid T.Text
luText = to _luText

instance FromJSON LambdaUuid where
  parseJSON =
    withText "LambdaUuid" $
      pure  LambdaUuid

data EventSourceStatus
  = EventSourceStatusPending
  | EventSourceStatusOk
  | EventSourceStatusProblem T.Text
  deriving (Eq, Show)

makePrisms ''EventSourceStatus

instance FromJSON EventSourceStatus where
  parseJSON =
    parserWithPrism "EventSourceStatus" $
      _String  _TextEventSourceStatus

eventSourceStatusToText
   EventSourceStatus
   T.Text
eventSourceStatusToText = \case
  EventSourceStatusPending  "PENDING"
  EventSourceStatusOk  "OK"
  EventSourceStatusProblem msg  "PROBLEM:"  msg

_TextEventSourceStatus  Prism' T.Text EventSourceStatus
_TextEventSourceStatus =
  prism eventSourceStatusToText $ \txt 
    case (T.unpack $ T.toUpper txt) of
      "PENDING"  Right EventSourceStatusPending
      "OK"  Right EventSourceStatusOk
      'P':'R':'O':'B':'L':'E':'M':':':msg  Right  EventSourceStatusProblem $ T.pack msg
      _  Left txt

data StreamPosition
  = StreamPositionTrimHorizon
  | StreamPositionLatest
  deriving (Eq, Show)

makePrisms ''StreamPosition

instance FromJSON StreamPosition where
  parseJSON =
    parserWithPrism "StreamPosition" $
      _String  _TextStreamPosition

instance ToJSON StreamPosition where
  toJSON = review $ _String  _TextStreamPosition

streamPositionToText
   StreamPosition
   T.Text
streamPositionToText = \case
  StreamPositionTrimHorizon  "TRIM_HORIZON"
  StreamPositionLatest  "LATEST"

_TextStreamPosition  Prism' T.Text StreamPosition
_TextStreamPosition =
  prism streamPositionToText $ \case
    "TRIM_HORIZON"  Right StreamPositionTrimHorizon
    "LATEST"  Right StreamPositionLatest
    txt  Left txt

newtype LambdaDateTime
  = LambdaDateTime
  { _ldtUTCTime  UTCTime
  } deriving (Eq, Ord, Show, ParseTime, FormatTime)

makePrisms ''LambdaDateTime

lambdaDateTimeFormat  String
lambdaDateTimeFormat = "%FT%T%Q%Z"

_TextLambdaDateTime  Prism' T.Text LambdaDateTime
_TextLambdaDateTime =
  prism (T.pack  formatTime defaultTimeLocale lambdaDateTimeFormat) $ \txt 
    case parseTime defaultTimeLocale lambdaDateTimeFormat (T.unpack txt) of
      Just dt  Right dt
      Nothing  Left txt

instance ToJSON LambdaDateTime where
  toJSON = review $ _String  _TextLambdaDateTime

instance FromJSON LambdaDateTime where
  parseJSON =
    parserWithPrism "LambdaDateTime" $
      _String  _TextLambdaDateTime

data EventSourceParameters
  = EventSourceParameters
  { _espInitialPositionInStream  !(Maybe StreamPosition)
  } deriving (Eq, Show)

makeLenses ''EventSourceParameters

instance FromJSON EventSourceParameters where
  parseJSON =
    withObject "EventSourceParameters" $ \o 
      pure EventSourceParameters
         o .:? "InitialPositionInStream"

instance ToJSON EventSourceParameters where
  toJSON EventSourceParameters{..} = Object $
    mempty
      & at "InitialPositionInStream" .~ _espInitialPositionInStream ^? _Just  to toJSON

data EventSourceConfiguration
  = EventSourceConfiguration
  { _escBatchSize  !(Maybe Int)
  , _escEventSource  !(Maybe Arn)
  , _escFunctionName  !(Maybe T.Text)
  , _escIsActive  !(Maybe Bool)
  , _escLastModified  !(Maybe LambdaDateTime)
  , _escParameters  !(Maybe EventSourceParameters)
  , _escRole  !(Maybe Arn)
  , _escStatus  !(Maybe EventSourceStatus)
  , _escUuid  !(Maybe LambdaUuid)
  } deriving (Eq, Show)

makeLenses ''EventSourceConfiguration

-- | A kludge to get around incorrectly formatted JSON in AWS Lambda responses.
--
boolParserKludge
   Object
   T.Text
   Parser Bool
boolParserKludge o k = o .: k <|> (fromString = o .: k)
  where
    fromString  T.Text  Parser Bool
    fromString = \case
      "true"  return True
      "false"  return False
      _  empty

instance FromJSON EventSourceConfiguration where
  parseJSON =
    withObject "EventSourceConfiguration" $ \o 
      pure EventSourceConfiguration
         o .:? "BatchSize"
         o .:? "EventSource"
         o .:? "FunctionName"
         optional (boolParserKludge o "IsActive")
         o .:? "LastModified"
         o .:? "Parameters"
         o .:? "Role"
         o .:? "Status"
         o .:? "UUID"

newtype ConfigurationId
  = ConfigurationId
  { _cidText  T.Text
  } deriving (Eq, Show, ToJSON)

cidText  Getter ConfigurationId T.Text
cidText = to _cidText

instance FromJSON ConfigurationId where
  parseJSON =
    withText "ConfigurationId" $
      pure  ConfigurationId

data FunctionMode
  = FunctionModeEvent
  deriving (Eq, Show)

makePrisms ''FunctionMode

instance FromJSON FunctionMode where
  parseJSON =
    parserWithPrism "FunctionMode" $
      _String  _TextFunctionMode

functionModeToText
   FunctionMode
   T.Text
functionModeToText = \case
  FunctionModeEvent  "event"

_TextFunctionMode  Prism' T.Text FunctionMode
_TextFunctionMode =
  prism functionModeToText $ \case
    "event"  Right FunctionModeEvent
    txt  Left txt

data FunctionRuntime
  = FunctionRuntimeNodeJs
  deriving (Eq, Show)

makePrisms ''FunctionRuntime

instance FromJSON FunctionRuntime where
  parseJSON =
    parserWithPrism "FunctionRuntime" $
      _String  _TextFunctionRuntime

functionRuntimeToText
   FunctionRuntime
   T.Text
functionRuntimeToText = \case
  FunctionRuntimeNodeJs  "nodejs"

_TextFunctionRuntime  Prism' T.Text FunctionRuntime
_TextFunctionRuntime =
  prism functionRuntimeToText $ \case
    "nodejs"  Right FunctionRuntimeNodeJs
    txt  Left txt

data FunctionConfiguration
  = FunctionConfiguration
  { _fcCodeSize  !(Maybe Integer)
  , _fcConfigurationId  !(Maybe ConfigurationId)
  , _fcDescription  !(Maybe T.Text)
  , _fcFunctionArn  !(Maybe Arn)
  , _fcFunctionName  !(Maybe T.Text)
  , _fcHandler  !(Maybe T.Text)
  , _fcLastModified  !(Maybe LambdaDateTime)
  , _fcMemorySize  !(Maybe Int)
  , _fcMode  !(Maybe FunctionMode)
  , _fcRole  !(Maybe Arn)
  , _fcRuntime  !(Maybe FunctionRuntime)
  , _fcTimeout  !(Maybe Int)
  } deriving (Eq, Show)

makeLenses ''FunctionConfiguration

-- | An empty 'FunctionConfiguration' object.
--
emptyFunctionConfiguration  FunctionConfiguration
emptyFunctionConfiguration = FunctionConfiguration
  { _fcCodeSize = Nothing
  , _fcConfigurationId = Nothing
  , _fcDescription = Nothing
  , _fcFunctionArn = Nothing
  , _fcFunctionName = Nothing
  , _fcHandler = Nothing
  , _fcLastModified = Nothing
  , _fcMemorySize = Nothing
  , _fcMode = Nothing
  , _fcRole = Nothing
  , _fcRuntime = Nothing
  , _fcTimeout = Nothing
  }

instance FromJSON FunctionConfiguration where
  parseJSON =
    withObject "FunctionConfiguration" $ \o  do
      pure FunctionConfiguration
         o .:? "CodeSize"
         o .:? "ConfigurationId"
         o .:? "Description"
         o .:? "FunctionARN"
         o .:? "FunctionName"
         o .:? "Handler"
         o .:? "LastModified"
         o .:? "MemorySize"
         o .:? "Mode"
         o .:? "Role"
         o .:? "Runtime"
         o .:? "Timeout"


data FunctionCodeLocation
  = FunctionCodeLocation
  { _fclLocation  !(Maybe T.Text)
    -- ^ The presigned URL you can use to download the function's @.zip@ file
    -- that you previously uploaded. The URL is valid for up to 10 minutes.

  , _fclRepositoryType  !(Maybe T.Text)
    -- ^ The repository from which you can download the function.
  } deriving (Eq, Show)

makeLenses ''FunctionCodeLocation

instance FromJSON FunctionCodeLocation where
  parseJSON =
    withObject "FunctionCodeLocation" $ \o 
      pure FunctionCodeLocation
         o .:? "Location"
         o .:? "RepositoryType"