{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Rollbar.Item.Data
    ( Data(..)
    , Context(..)
    , Fingerprint(..)
    , Framework(..)
    , Title(..)
    , UUID4(..)
    , RemoveHeaders
    ) where
import Data.Aeson
    ( FromJSON
    , ToJSON
    , Value(String)
    , defaultOptions
    , genericParseJSON
    , genericToEncoding
    , genericToJSON
    , parseJSON
    , toEncoding
    , toJSON
    )
import Data.Aeson.Types
    (Options, fieldLabelModifier, omitNothingFields, typeMismatch)
import Data.String      (IsString)
import Data.Time        (UTCTime)
import Data.UUID        (UUID, fromText, toText)
import GHC.Generics (Generic)
import Rollbar.Item.Body        (Body)
import Rollbar.Item.CodeVersion (CodeVersion)
import Rollbar.Item.Environment (Environment)
import Rollbar.Item.Hardcoded   (Hardcoded)
import Rollbar.Item.Level       (Level)
import Rollbar.Item.Person      (Person)
import Rollbar.Item.Request     (RemoveHeaders, Request)
import Rollbar.Item.Server      (Server)
import Rollbar.Item.Internal.Notifier (Notifier)
import Rollbar.Item.Internal.Platform (Platform)
import qualified Data.HashMap.Lazy as HM
import qualified Data.Text         as T
data Data body headers
    = Data
        { body        :: Body body
        , codeVersion :: Maybe CodeVersion
        , context     :: Maybe Context
        , custom      :: Maybe (HM.HashMap T.Text Value)
        , environment :: Environment
        , fingerprint :: Maybe Fingerprint
        , framework   :: Maybe Framework
        , language    :: Hardcoded "haskell"
        , level       :: Level
        , notifier    :: Notifier
        
        , person      :: Maybe Person
        , platform    :: Platform
        
        , request     :: Maybe (Request headers)
        , server      :: Maybe Server
        , timestamp   :: Maybe UTCTime
        , title       :: Maybe Title
        , uuid        :: Maybe UUID4
        }
    deriving (Eq, Generic, Show)
instance FromJSON body => FromJSON (Data body headers) where
    parseJSON = genericParseJSON options
instance (RemoveHeaders headers, ToJSON body) => ToJSON (Data body headers) where
    toJSON = genericToJSON options
    toEncoding = genericToEncoding options
options :: Options
options = defaultOptions
    { fieldLabelModifier = codeVersionModifier
    , omitNothingFields = True
    }
codeVersionModifier :: (Eq s, IsString s) => s -> s
codeVersionModifier = \case
    "codeVersion" -> "code_version"
    str -> str
newtype Framework
    = Framework T.Text
    deriving (Eq, FromJSON, IsString, Show, ToJSON)
newtype Context
    = Context T.Text
    deriving (Eq, FromJSON, IsString, Show, ToJSON)
newtype Fingerprint
    = Fingerprint T.Text
    deriving (Eq, FromJSON, IsString, Show, ToJSON)
newtype Title
    = Title T.Text
    deriving (Eq, FromJSON, IsString, Show, ToJSON)
newtype UUID4
    = UUID4 UUID
    deriving (Eq, Generic, Show)
instance FromJSON UUID4 where
    parseJSON v@(String s) =
        maybe (typeMismatch "UUID4" v) (pure . UUID4) $ fromText s
    parseJSON v = typeMismatch "UUID4" v
instance ToJSON UUID4 where
    toJSON (UUID4 u) = toJSON (toText u)
    toEncoding (UUID4 u) = toEncoding (toText u)