module Web.Minion.Request.Url (capture, captures, piece) where

import Control.Monad.Catch (MonadThrow (throwM))
import Data.Bifunctor (Bifunctor (..))
import Data.String (IsString (..))
import Data.String.Conversions (ConvertibleStrings (..))
import Data.Text (Text)
import Network.HTTP.Types qualified as Http
import Web.HttpApiData (FromHttpApiData (parseUrlPiece), parseUrlPieces)
import Web.Minion.Args.Internal
import Web.Minion.Introspect qualified as I
import Web.Minion.Router.Internal

{- | Captures one piece of path

@
'capture' \@Text '.>' ...
@
-}
{-# INLINE capture #-}
capture ::
  forall b m i ts.
  (FromHttpApiData b, I.Introspection i I.Capture b, MonadThrow m) =>
  -- } .
  Text ->
  ValueCombinator i (WithPiece b) ts m
capture :: forall b (m :: * -> *) i ts.
(FromHttpApiData b, Introspection i 'Capture b, MonadThrow m) =>
Text -> ValueCombinator i (WithPiece b) ts m
capture =
  forall a ts (m :: * -> *) i.
Introspection i 'Capture a =>
(MakeError -> Text -> m a)
-> Text -> Router' i (ts :+ WithPiece a) m -> Router' i ts m
Capture @b
    ( \MakeError
makeError ->
        (ServerError -> m b) -> (b -> m b) -> Either ServerError b -> m b
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ServerError -> m b
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM b -> m b
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
          (Either ServerError b -> m b)
-> (Text -> Either ServerError b) -> Text -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> ServerError) -> Either Text b -> Either ServerError b
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (MakeError
makeError Status
Http.status400 (ByteString -> ServerError)
-> (Text -> ByteString) -> Text -> ServerError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
forall a b. ConvertibleStrings a b => a -> b
convertString)
          (Either Text b -> Either ServerError b)
-> (Text -> Either Text b) -> Text -> Either ServerError b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either Text b
forall a. FromHttpApiData a => Text -> Either Text a
parseUrlPiece
    )

{- | Captures the rest of path

@
'captures' \@Text '.>' ...
@
-}
{-# INLINE captures #-}
captures ::
  forall b m i ts.
  (FromHttpApiData b, I.Introspection i I.Captures b, MonadThrow m) =>
  -- | .
  Text ->
  ValueCombinator i (WithPieces b) ts m
captures :: forall b (m :: * -> *) i ts.
(FromHttpApiData b, Introspection i 'Captures b, MonadThrow m) =>
Text -> ValueCombinator i (WithPieces b) ts m
captures =
  forall a ts (m :: * -> *) i.
Introspection i 'Captures a =>
(MakeError -> [Text] -> m [a])
-> Text -> Router' i (ts :+ WithPieces a) m -> Router' i ts m
Captures @b
    \MakeError
makeError ->
      (ServerError -> m [b])
-> ([b] -> m [b]) -> Either ServerError [b] -> m [b]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ServerError -> m [b]
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
throwM [b] -> m [b]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
        (Either ServerError [b] -> m [b])
-> ([Text] -> Either ServerError [b]) -> [Text] -> m [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> ServerError) -> Either Text [b] -> Either ServerError [b]
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (MakeError
makeError Status
Http.status400 (ByteString -> ServerError)
-> (Text -> ByteString) -> Text -> ServerError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
forall a b. ConvertibleStrings a b => a -> b
convertString)
        (Either Text [b] -> Either ServerError [b])
-> ([Text] -> Either Text [b]) -> [Text] -> Either ServerError [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Either Text [b]
forall (t :: * -> *) a.
(Traversable t, FromHttpApiData a) =>
t Text -> Either Text (t a)
parseUrlPieces

{- | Could be omitted with `OverloadedStrings`

@
{\-# LANGUAGE OverloadedStrings #-\}
"bar" '/>' ...
@

@
{\-# LANGUAGE NoOverloadedStrings #-\}
'piece' "bar" '/>' ...
@

Also splits piece with /, so

@
piece "foo\/bar\/bar" == piece "foo" '/>' piece "bar" '/>' piece "baz"
"foo\/bar\/baz" == "foo" '/>' "bar" '/>' "baz"
@
-}
{-# INLINE piece #-}
piece :: String -> Combinator i ts m
piece :: forall i ts (m :: * -> *). String -> Combinator i ts m
piece = String -> Combinator i ts m
forall a. IsString a => String -> a
fromString