    {-# LANGUAGE LambdaCase        #-}
    {-# LANGUAGE OverloadedStrings #-}
    {- |
    Copyright               : © 2021-2025 Albert Krewinkel
    SPDX-License-Identifier : MIT
    Maintainer              : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>

    Defines a helper type that can handle different types of 'Block' and
    'Inline' element contents.
    -}
    module Text.Pandoc.Lua.Marshal.Content
      ( Content (..)
      , contentTypeDescription
      , peekContent
      , pushContent
      , peekDefinitionItem
      ) where

    import Control.Applicative ((<|>))
    import Control.Monad ((<$!>))
    import HsLua
    import {-# SOURCE #-} Text.Pandoc.Lua.Marshal.Block
      ( peekBlocksFuzzy, pushBlocks )
    import {-# SOURCE #-} Text.Pandoc.Lua.Marshal.Inline
      ( peekInlinesFuzzy, pushInlines )
    import Text.Pandoc.Lua.Marshal.List (pushPandocList)
    import Text.Pandoc.Definition (Inline, Block)

    --
    -- Content
    --

    -- | Helper type to represent all the different types a `content`
    -- attribute can have.
    data Content
      = ContentBlocks [Block]
      | ContentInlines [Inline]
      | ContentLines [[Inline]]
      | ContentDefItems [([Inline], [[Block]])]
      | ContentListItems [[Block]]

    -- | Returns a human-readable type description; used for error messages.
    contentTypeDescription :: Content -> String
    contentTypeDescription :: Content -> String
    contentTypeDescription = \case
      ContentBlocks {}    -> String
    "list of Block items"
      ContentInlines {}   -> String
    "list of Inline items"
      ContentLines {}     -> String
    "list of Inline lists (i.e., a list of lines)"
      ContentDefItems {}  -> String
    "list of definition items items"
      ContentListItems {} -> String
    "list items (i.e., list of list of Block elements)"

    -- | Pushes the 'Content' to the stack.
    pushContent :: LuaError e => Pusher e Content
    pushContent :: forall e. LuaError e => Pusher e Content
    pushContent = \case
      ContentBlocks [Block]
    blks    -> Pusher e [Block]
    forall e. LuaError e => Pusher e [Block]
    pushBlocks [Block]
    blks
      ContentInlines [Inline]
    inlns  -> Pusher e [Inline]
    forall e. LuaError e => Pusher e [Inline]
    pushInlines [Inline]
    inlns
      ContentLines [[Inline]]
    lns      -> Pusher e [Inline] -> Pusher e [[Inline]]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e [Inline]
    forall e. LuaError e => Pusher e [Inline]
    pushInlines [[Inline]]
    lns
      ContentDefItems [([Inline], [[Block]])]
    itms  -> Pusher e ([Inline], [[Block]]) -> Pusher e [([Inline], [[Block]])]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e ([Inline], [[Block]])
    forall e. LuaError e => Pusher e ([Inline], [[Block]])
    pushDefinitionItem [([Inline], [[Block]])]
    itms
      ContentListItems [[Block]]
    itms -> Pusher e [Block] -> Pusher e [[Block]]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e [Block]
    forall e. LuaError e => Pusher e [Block]
    pushBlocks [[Block]]
    itms

    -- | Gets a 'Content' element from the stack.
    peekContent :: LuaError e => Peeker e Content
    peekContent :: forall e. LuaError e => Peeker e Content
    peekContent StackIndex
    idx =
      ([Inline] -> Content
    ContentInlines ([Inline] -> Content) -> Peek e [Inline] -> Peek e Content
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e [Inline]
    forall e. LuaError e => Peeker e [Inline]
    peekInlinesFuzzy StackIndex
    idx) Peek e Content -> Peek e Content -> Peek e Content
    forall a. Peek e a -> Peek e a -> Peek e a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
      ([[Inline]] -> Content
    ContentLines  ([[Inline]] -> Content) -> Peek e [[Inline]] -> Peek e Content
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e [Inline] -> Peeker e [[Inline]]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e [Inline]
    forall e. LuaError e => Peeker e [Inline]
    peekInlinesFuzzy StackIndex
    idx) Peek e Content -> Peek e Content -> Peek e Content
    forall a. Peek e a -> Peek e a -> Peek e a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
      ([Block] -> Content
    ContentBlocks  ([Block] -> Content) -> Peek e [Block] -> Peek e Content
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e [Block]
    forall e. LuaError e => Peeker e [Block]
    peekBlocksFuzzy StackIndex
    idx ) Peek e Content -> Peek e Content -> Peek e Content
    forall a. Peek e a -> Peek e a -> Peek e a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
      ([[Block]] -> Content
    ContentListItems ([[Block]] -> Content) -> Peek e [[Block]] -> Peek e Content
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e [Block] -> Peeker e [[Block]]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e [Block]
    forall e. LuaError e => Peeker e [Block]
    peekBlocksFuzzy StackIndex
    idx) Peek e Content -> Peek e Content -> Peek e Content
    forall a. Peek e a -> Peek e a -> Peek e a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|>
      ([([Inline], [[Block]])] -> Content
    ContentDefItems  ([([Inline], [[Block]])] -> Content)
    -> Peek e [([Inline], [[Block]])] -> Peek e Content
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e ([Inline], [[Block]]) -> Peeker e [([Inline], [[Block]])]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e ([Inline], [[Block]])
    forall e. LuaError e => Peeker e ([Inline], [[Block]])
    peekDefinitionItem StackIndex
    idx)

    -- | Retrieves a single definition item from the stack; it is expected
    -- to be a pair of a list of inlines and a list of list of blocks. Uses
    -- fuzzy parsing, i.e., tries hard to convert mismatching types into the
    -- expected result.
    peekDefinitionItem :: LuaError e => Peeker e ([Inline], [[Block]])
    peekDefinitionItem :: forall e. LuaError e => Peeker e ([Inline], [[Block]])
    peekDefinitionItem = Peeker e [Inline]
    -> Peeker e [[Block]] -> Peeker e ([Inline], [[Block]])
    forall e a b.
    LuaError e =>
    Peeker e a -> Peeker e b -> Peeker e (a, b)
    peekPair Peeker e [Inline]
    forall e. LuaError e => Peeker e [Inline]
    peekInlinesFuzzy (Peeker e [[Block]] -> Peeker e ([Inline], [[Block]]))
    -> Peeker e [[Block]] -> Peeker e ([Inline], [[Block]])
    forall a b. (a -> b) -> a -> b
    $ [Peeker e [[Block]]] -> Peeker e [[Block]]
    forall e a. LuaError e => [Peeker e a] -> Peeker e a
    choice
      [ Peeker e [Block] -> Peeker e [[Block]]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e [Block]
    forall e. LuaError e => Peeker e [Block]
    peekBlocksFuzzy
      , \StackIndex
    idx -> ([Block] -> [[Block]] -> [[Block]]
    forall a. a -> [a] -> [a]
    :[]) ([Block] -> [[Block]]) -> Peek e [Block] -> Peek e [[Block]]
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> Peeker e [Block]
    forall e. LuaError e => Peeker e [Block]
    peekBlocksFuzzy StackIndex
    idx
      ]

    -- | Pushes a single definition items on the stack.
    pushDefinitionItem :: LuaError e => Pusher e ([Inline], [[Block]])
    pushDefinitionItem :: forall e. LuaError e => Pusher e ([Inline], [[Block]])
    pushDefinitionItem = Pusher e [Inline]
    -> Pusher e [[Block]] -> ([Inline], [[Block]]) -> LuaE e ()
    forall e a b.
    LuaError e =>
    Pusher e a -> Pusher e b -> (a, b) -> LuaE e ()
    pushPair Pusher e [Inline]
    forall e. LuaError e => Pusher e [Inline]
    pushInlines
                                  (Pusher e [Block] -> Pusher e [[Block]]
    forall e a. LuaError e => Pusher e a -> Pusher e [a]
    pushPandocList Pusher e [Block]
    forall e. LuaError e => Pusher e [Block]
    pushBlocks)