module Simplex.Messaging.Agent.QueryString
  ( QueryStringParams (..),
    QSPEscaping (..),
    queryParam,
    queryParamParser,
    queryParam_,
    queryParamStr,
  ) where

import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.List (find)
import qualified Network.HTTP.Types as Q
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll)

data QueryStringParams = QSP QSPEscaping Q.SimpleQuery
  deriving (Show)

data QSPEscaping = QEscape | QNoEscaping
  deriving (Show)

instance StrEncoding QueryStringParams where
  strEncode (QSP esc q) = case esc of
    QEscape -> Q.renderSimpleQuery False q
    QNoEscaping ->
      Q.renderQueryPartialEscape False $
        map (\(n, v) -> (n, [Q.QN v])) q
  strP = QSP QEscape . Q.parseSimpleQuery <$> A.takeTill (\c -> c == ' ' || c == '\n')

queryParam :: StrEncoding a => ByteString -> QueryStringParams -> Parser a
queryParam = queryParamParser strP

queryParamParser :: Parser a -> ByteString -> QueryStringParams -> Parser a
queryParamParser p name q =
  case queryParamStr name q of
    Just s -> either fail pure $ parseAll p s
    _ -> fail $ "no qs param " <> B.unpack name

queryParam_ :: StrEncoding a => ByteString -> QueryStringParams -> Parser (Maybe a)
queryParam_ name q =
  case queryParamStr name q of
    Just p -> either fail pure $ parseAll strP p
    _ -> pure Nothing

queryParamStr :: ByteString -> QueryStringParams -> Maybe ByteString
queryParamStr name (QSP _ q) = snd <$> find ((== name) . fst) q
