{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Network.Bugsnag.Event
    ( BugsnagEvent(..)
    , bugsnagEvent
    ) where

import Data.Aeson
import Data.Aeson.Types
import Data.Text (Text)
import Network.Bugsnag.App
import Network.Bugsnag.Breadcrumb
import Network.Bugsnag.Device
import Network.Bugsnag.Exception
import Network.Bugsnag.Request
import Network.Bugsnag.Severity
import Network.Bugsnag.Thread
import Network.Bugsnag.User

data BugsnagEvent = BugsnagEvent
    { beException :: BugsnagException
    , beBreadcrumbs :: Maybe [BugsnagBreadcrumb]
    , beRequest :: Maybe BugsnagRequest
    , beThreads :: Maybe [BugsnagThread]
    , beContext :: Maybe Text
    , beGroupingHash :: Maybe Text
    , beUnhandled :: Maybe Bool
    , beSeverity :: Maybe BugsnagSeverity
    , beSeverityReason :: Maybe BugsnagSeverityReason
    , beUser :: Maybe BugsnagUser
    , beApp :: Maybe BugsnagApp
    , beDevice :: Maybe BugsnagDevice
    --, beSession
    -- N.B. omitted because it's an object specific to the Session Tracking API,
    -- and I'm not sure yet how to resolve the naming clash with BugsnagSession.
    , beMetaData :: Maybe Value
    }

instance ToJSON BugsnagEvent where
    -- | Explicit instance needed to send @'beException'@ as @exceptions@
    toJSON BugsnagEvent {..} = object
        $ "exceptions" .= [beException]
        : concat
            [ "breadcrumbs" .=? beBreadcrumbs
            , "request" .=? beRequest
            , "threads" .=? beThreads
            , "context" .=? beContext
            , "groupingHash" .=? beGroupingHash
            , "unhandled" .=? beUnhandled
            , "severity" .=? beSeverity
            , "severityReason" .=? beSeverityReason
            , "user" .=? beUser
            , "app" .=? beApp
            , "device" .=? beDevice
            , "metaData" .=? beMetaData
            ]
      where
        -- For implementing "omit Nothing fields"
        (.=?) :: ToJSON v => Text -> Maybe v -> [Pair]
        (.=?) k = maybe [] (pure . (k .=))

bugsnagEvent :: BugsnagException -> BugsnagEvent
bugsnagEvent exception = BugsnagEvent
    { beException = exception
    , beBreadcrumbs = Nothing
    , beRequest = Nothing
    , beThreads = Nothing
    , beContext = Nothing
    , beGroupingHash = Nothing
    , beUnhandled = Nothing
    , beSeverity = Nothing
    , beSeverityReason = Nothing
    , beUser = Nothing
    , beApp = Nothing
    , beDevice = Nothing
    , beMetaData = Nothing
    }