-- |
-- Renders a 'Block' without doing 'IO'. Uses a 'Text.Lazy.Text' so wrapping is
-- easier to implement. The absolute majority of the time is spent going from
-- 'Text.Lazy.Text' to 'Builder' and back. If we strip out 'Builder' we gain
-- complexity like crazy. Suggestions welcome.
renderBlockPure :: PrettyPrintOptions -> Block -> Text.Lazy.Text
renderBlockPure opts@PrettyPrintOptions{..} block = case block of
    (Header level els) ->
        setSGRCodeText [ SetColor Foreground Vivid Black
                    , SetConsoleIntensity BoldIntensity
                    ] <>
        Text.Lazy.replicate (fromIntegral level) "#" <> " " <>
        setSGRCodeText [ Reset ] <>
        setSGRCodeText [ SetColor Foreground Vivid Cyan
                       , SetConsoleIntensity BoldIntensity
                       ] <>
        toLazyText (mconcatMapF renderInline els) <>
        setSGRCodeText [ Reset ] <>
        "\n"
    (Para els) ->
        wordwrap prettyPrintWidth (toLazyText (mconcatMapF renderInline els))
    (List _ (Bullet c) bss) -> flip mconcatMapF bss $
        \bs -> setSGRCodeText [ SetColor Foreground Vivid Black ] <>
               Text.Lazy.pack ("  " ++ (c:" ")) <>
               setSGRCodeText [ Reset ] <>
               mconcatMapF (renderBlockPure opts) bs
    (List _ (Numbered w i) bss) ->
        let ibss = zip bss [0..]
        in flip mconcatMapF ibss $ \(bs, j) ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        let wc = case w of
                PeriodFollowing -> '.'
                ParenFollowing -> ')'
         in Text.Lazy.pack ("  " ++ show (i + j) ++ (wc : " ")) <>
        setSGRCodeText [ Reset ] <>
        mconcatMapF (renderBlockPure opts) bs
    (Blockquote bs) -> flip mconcatMapF bs $ \b ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        "  > " <>
        setSGRCodeText [ SetColor Foreground Vivid Blue ] <>
        renderBlockPure opts b
    (CodeBlock (CodeAttr "haskell" _) t) ->
        let code = hscolour
                TTY prettyPrintColourPrefs False True "" False (Text.unpack t)
        in toLazyText (mconcatMapF ((<> "\n") . ("    " <>) . fromString) (lines code))
    (CodeBlock (CodeAttr _ _) t) ->
        setSGRCodeText [ SetColor Foreground Dull Yellow ] <>
        mconcat (map (Text.Lazy.fromStrict . (<> "\n") . ("    " <>) ) (Text.lines t)) <>
        setSGRCodeText [ Reset ]
    HRule ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        Text.Lazy.replicate (fromIntegral prettyPrintWidth) "-" <>
        setSGRCodeText [ Reset ]
    (HtmlBlock html) -> Text.Lazy.fromStrict html <> "\n"

-- |
-- Renders an inline to a 'Text' 'Builder'
renderBlockPure :: PrettyPrintOptions -> Block -> Text.Lazy.Text
renderBlockPure opts@PrettyPrintOptions{..} block = case block of
    (Header level els) ->
        setSGRCodeText [ SetColor Foreground Vivid Black
                    , SetConsoleIntensity BoldIntensity
                    ] <>
        Text.Lazy.replicate (fromIntegral level) "#" <> " " <>
        setSGRCodeText [ Reset ] <>
        setSGRCodeText [ SetColor Foreground Vivid Cyan
                       , SetConsoleIntensity BoldIntensity
                       ] <>
        toLazyText (mconcatMapF renderInline els) <>
        setSGRCodeText [ Reset ] <>
        "\n"
    (Para els) ->
        wordwrap prettyPrintWidth (toLazyText (mconcatMapF renderInline els))
    (List _ (Bullet c) bss) -> flip mconcatMapF bss $
        \bs -> setSGRCodeText [ SetColor Foreground Vivid Black ] <>
               Text.Lazy.pack ("  " ++ (c:" ")) <>
               setSGRCodeText [ Reset ] <>
               mconcatMapF (renderBlockPure opts) bs
    (List _ (Numbered w i) bss) ->
        let ibss = zip bss [0..]
        in flip mconcatMapF ibss $ \(bs, j) ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        let wc = case w of
                PeriodFollowing -> '.'
                ParenFollowing -> ')'
         in Text.Lazy.pack ("  " ++ show (i + j) ++ (wc : " ")) <>
        setSGRCodeText [ Reset ] <>
        mconcatMapF (renderBlockPure opts) bs
    (Blockquote bs) -> flip mconcatMapF bs $ \b ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        "  > " <>
        setSGRCodeText [ SetColor Foreground Vivid Blue ] <>
        renderBlockPure opts b
    (CodeBlock (CodeAttr "haskell" _) t) ->
        let code = hscolour
                TTY prettyPrintColourPrefs False True "" False (Text.unpack t)
        in toLazyText (mconcatMapF ((<> "\n") . ("    " <>) . fromString) (lines code))
    (CodeBlock (CodeAttr _ _) t) ->
        setSGRCodeText [ SetColor Foreground Dull Yellow ] <>
        mconcat (map (Text.Lazy.fromStrict . (<> "\n") . ("    " <>) ) (Text.lines t)) <>
        setSGRCodeText [ Reset ]
    HRule ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        Text.Lazy.replicate (fromIntegral prettyPrintWidth) "-" <>
        setSGRCodeText [ Reset ]
    (HtmlBlock html) -> Text.Lazy.fromStrict html <> "\n"

-- |
-- Renders an inline to a 'Text' 'Builder'
renderBlockPure opts@PrettyPrintOptions{..} block = case block of
    (Header level els) ->
        setSGRCodeText [ SetColor Foreground Vivid Black
                    , SetConsoleIntensity BoldIntensity
                    ] <>
        Text.Lazy.replicate (fromIntegral level) "#" <> " " <>
        setSGRCodeText [ Reset ] <>
        setSGRCodeText [ SetColor Foreground Vivid Cyan
                       , SetConsoleIntensity BoldIntensity
                       ] <>
        toLazyText (mconcatMapF renderInline els) <>
        setSGRCodeText [ Reset ] <>
        "\n"
    (Para els) ->
        wordwrap prettyPrintWidth (toLazyText (mconcatMapF renderInline els))
    (List _ (Bullet c) bss) -> flip mconcatMapF bss $
        \bs -> setSGRCodeText [ SetColor Foreground Vivid Black ] <>
               Text.Lazy.pack ("  " ++ (c:" ")) <>
               setSGRCodeText [ Reset ] <>
               mconcatMapF (renderBlockPure opts) bs
    (List _ (Numbered w i) bss) ->
        let ibss = zip bss [0..]
        in flip mconcatMapF ibss $ \(bs, j) ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        let wc = case w of
                PeriodFollowing -> '.'
                ParenFollowing -> ')'
         in Text.Lazy.pack ("  " ++ show (i + j) ++ (wc : " ")) <>
        setSGRCodeText [ Reset ] <>
        mconcatMapF (renderBlockPure opts) bs
    (Blockquote bs) -> flip mconcatMapF bs $ \b ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        "  > " <>
        setSGRCodeText [ SetColor Foreground Vivid Blue ] <>
        renderBlockPure opts b
    (CodeBlock (CodeAttr "haskell" _) t) ->
        let code = hscolour
                TTY prettyPrintColourPrefs False True "" False (Text.unpack t)
        in toLazyText (mconcatMapF ((<> "\n") . ("    " <>) . fromString) (lines code))
    (CodeBlock (CodeAttr _ _) t) ->
        setSGRCodeText [ SetColor Foreground Dull Yellow ] <>
        mconcat (map (Text.Lazy.fromStrict . (<> "\n") . ("    " <>) ) (Text.lines t)) <>
        setSGRCodeText [ Reset ]
    HRule ->
        setSGRCodeText [ SetColor Foreground Vivid Black ] <>
        Text.Lazy.replicate (fromIntegral prettyPrintWidth) "-" <>
        setSGRCodeText [ Reset ]
    (HtmlBlock html) -> Text.Lazy.fromStrict html <> "\n"

-- |
-- Renders an inline to a 'Text' 'Builder'