{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Rollbar.Item.MissingHeaders
    ( MissingHeaders(..)
    , RemoveHeaders
    ) where
import Data.Aeson
    (FromJSON, KeyValue, ToJSON, object, parseJSON, toJSON, (.=))
import Data.Bifunctor       (bimap)
import Data.CaseInsensitive (mk, original)
import Data.Maybe           (catMaybes)
import Data.Proxy           (Proxy(Proxy))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import Network.HTTP.Types (Header, RequestHeaders)
import qualified Data.ByteString       as BS
import qualified Data.ByteString.Char8 as BSC8
import qualified Data.Text             as T
import qualified Data.Text.Encoding    as TE
newtype MissingHeaders (headers :: [Symbol])
    = MissingHeaders RequestHeaders
    deriving (Eq, Show)
class RemoveHeaders (headers :: [Symbol]) where
    removeHeaders :: MissingHeaders headers -> RequestHeaders
instance RemoveHeaders '[] where
    removeHeaders (MissingHeaders rhs) = rhs
instance (KnownSymbol header, RemoveHeaders headers)
    => RemoveHeaders (header ': headers) where
    removeHeaders (MissingHeaders rhs) =
        removeHeaders (MissingHeaders $ filter go rhs :: MissingHeaders headers)
        where
        go (rh, _) =
            rh /= (mk . BSC8.pack $ symbolVal (Proxy :: Proxy header))
instance FromJSON (MissingHeaders headers) where
    parseJSON v = MissingHeaders . fmap (bimap (mk . BS.pack) BS.pack) <$> parseJSON v
instance RemoveHeaders headers => ToJSON (MissingHeaders headers) where
    toJSON = object . catMaybes . requestHeadersKVs . removeHeaders
requestHeadersKVs :: forall kv. KeyValue kv => RequestHeaders -> [Maybe kv]
requestHeadersKVs = fmap go
    where
    go :: Header -> Maybe kv
    go (key', val') = do
        key <- myDecodeUtf8 $ original key'
        val <- myDecodeUtf8 val'
        pure (key .= val)
myDecodeUtf8 :: BS.ByteString -> Maybe T.Text
myDecodeUtf8 = either (const Nothing) Just . TE.decodeUtf8'