{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}

import ChaoDoc
-- import Data.Either
-- import Data.Functor
-- import qualified Data.Map as M
import qualified Data.Text as T
import Hakyll
-- import System.IO.Unsafe
import Text.Pandoc
-- import Text.Pandoc.Citeproc
import System.FilePath

--------------------------------------------------------------------------------
-- https://www.rohanjain.in/hakyll-clean-urls/
cleanRoute :: Routes
cleanRoute = customRoute createIndexRoute
  where
    createIndexRoute ident = takeDirectory p </> takeBaseName p </> "index.html"
                            where p = toFilePath ident

cleanIndexHtmls :: Item String -> Compiler (Item String)
cleanIndexHtmls = return . fmap (replaceAll pattern replacement)
    where
      pattern::String = "/index.html"
      replacement::String->String = const "/"

--------------------------------------------------------------------------------
root:: String
root = ""

main :: IO ()
main = hakyll $ do
  match "images/**" $ do
    route idRoute
    compile copyFileCompiler

  -- match "mathjax/**" $ do
  --   route idRoute
  --   compile copyFileCompiler

  -- match "mathjax-fira-font/**" $ do
  --   route idRoute
  --   compile copyFileCompiler

  match "fonts/*" $ do
    route idRoute
    compile copyFileCompiler

  match "404.html" $ do
    route cleanRoute
    compile copyFileCompiler

  match "css/*" $ do
    route idRoute
    compile compressCssCompiler

  match "index.md" $ do
    route $ setExtension "html"
    compile $ do
      tocCtx <- getTocCtx defaultContext
      chaoDocCompiler
        >>= loadAndApplyTemplate "templates/index.html" (tocCtx `mappend` constField "root" root)
        >>= relativizeUrls
        >>= cleanIndexHtmls

  match ( fromList["talks.md","invited_speaker.md","registration.md","program.md","venue.md","travel.md","social_event.md","contact.md","about.md"] ) $ do
    route cleanRoute
    compile $ do
      tocCtx <- getTocCtx defaultContext
      chaoDocCompiler
        >>= loadAndApplyTemplate "templates/standalone.html" (tocCtx `mappend` constField "root" root)
        >>= relativizeUrls

  -- -- build up tags
  -- tags <- buildTags "posts/*" (fromCapture "tags/*.html")
  -- tagsRules tags $ \tag pattern -> do
  --   let title = "Posts tagged \"" ++ tag ++ "\""
  --   route cleanRoute
  --   compile $ do
  --     posts <- recentFirst =<< loadAll pattern
  --     let ctx =
  --           constField "title" title
  --             `mappend` listField "posts" (postCtxWithTags tags) (return posts)
  --             `mappend` defaultContext
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/tag.html" ctx
  --       >>= loadAndApplyTemplate "templates/default.html" ctx
  --       >>= relativizeUrls

  -- create ["tags.html"] $ do
  --   route cleanRoute
  --   compile $ do
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/tags.html" (defaultCtxWithTags tags)
  --       >>= loadAndApplyTemplate "templates/default.html" (defaultCtxWithTags tags)

  -- match "posts/*" $ do
  --   route cleanRoute
  --   compile $ do
  --     tocCtx <- getTocCtx (postCtxWithTags tags)
  --     chaoDocCompiler
  --       >>= loadAndApplyTemplate "templates/post.html" tocCtx
  --       >>= loadAndApplyTemplate "templates/default.html" tocCtx
  --       >>= relativizeUrls
  --       -- >>= katexFilter  -- use mathjax.

  -- match "standalone/*" $ do
  --   route cleanRoute
  --   compile $ do
  --     tocCtx <- getTocCtx (postCtxWithTags tags)
  --     chaoDocCompiler
  --       >>= loadAndApplyTemplate "templates/standalone.html" tocCtx
  --       >>= relativizeUrls

  -- create ["notes.html"] $ do
  --   route cleanRoute
  --   compile $ do
  --     notes <- recentFirst =<< loadAll "standalone/*"
  --     let notesCtx =
  --           listField "posts" postCtx (return notes)
  --             `mappend` constField "title" "Notes"
  --             `mappend` defaultContext
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/notes.html" notesCtx
  --       >>= loadAndApplyTemplate "templates/index.html" notesCtx
  --       >>= relativizeUrls
  --       >>= cleanIndexHtmls

  -- create ["archive.html"] $ do
  --   route cleanRoute
  --   compile $ do
  --     posts <- recentFirst =<< loadAll "posts/*"
  --     let archiveCtx =
  --           listField "posts" postCtx (return posts)
  --             `mappend` constField "title" "Archives"
  --             `mappend` defaultContext
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/archive.html" archiveCtx
  --       >>= loadAndApplyTemplate "templates/index.html" archiveCtx
  --       >>= relativizeUrls
  --       >>= cleanIndexHtmls

  -- create ["draft.html"] $ do
  --   route cleanRoute
  --   compile $ do
  --     posts <- recentFirst =<< loadAll "posts/*"
  --     let draftCtx =
  --           listField "posts" postCtx (return posts)
  --             `mappend` constField "title" "Drafts"
  --             `mappend` defaultContext
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/draft.html" draftCtx
  --       >>= loadAndApplyTemplate "templates/index.html" draftCtx
  --       >>= relativizeUrls
  --       >>= cleanIndexHtmls

  -- match "index.html" $ do
  --   route idRoute
  --   compile $ do
  --     posts <- fmap (take 25) . recentFirst =<< loadAll "posts/*"
  --     let indexCtx =
  --           listField "posts" postCtx (return posts)
  --             `mappend` defaultContext
  --     getResourceBody
  --       >>= applyAsTemplate indexCtx
  --       >>= loadAndApplyTemplate "templates/index.html" indexCtx
  --       >>= relativizeUrls
  --       >>= cleanIndexHtmls

  match "templates/*" $ compile templateBodyCompiler

  -- https://robertwpearce.com/hakyll-pt-2-generating-a-sitemap-xml-file.html
  -- create ["sitemap.xml"] $ do
  --   route idRoute
  --   compile $ do
  --     posts <- recentFirst =<< loadAll "posts/*"
  --     singlePages <- loadAll (fromList ["about.md"])
  --     let pages = posts <> singlePages
  --         sitemapCtx =
  --           constField "root" root
  --             <> listField "pages" postCtx (return pages) -- here
  --     makeItem ""
  --       >>= loadAndApplyTemplate "templates/sitemap.xml" sitemapCtx

--------------------------------------------------------------------------------

postCtx :: Context String
postCtx =
  dateField "date" "%B %e, %Y"
    -- <> constField "root" root
    <> dateField "date" "%Y-%m-%d"
    <> defaultContext

postCtxWithTags :: Tags -> Context String
postCtxWithTags tags = tagsField "tags" tags `mappend` postCtx

defaultCtxWithTags :: Tags -> Context String
defaultCtxWithTags tags = listField "tags" tagsCtx getAllTags <> defaultContext
  where
    getAllTags :: Compiler [Item (String, [Identifier])]
    getAllTags = pure . map mkItem $ tagsMap tags
      where
        mkItem :: (String, [Identifier]) -> Item (String, [Identifier])
        mkItem x@(t, _) = Item (tagsMakeId tags t) x
    tagsCtx =
      listFieldWith "posts" (postCtxWithTags tags) getPosts
        <> metadataField
        <> urlField "url"
        <> pathField "path"
        <> titleField "title"
        <> missingField
      where
        getPosts ::
          Item (String, [Identifier]) ->
          Compiler [Item String]
        getPosts (itemBody -> (_, is)) = mapM load is


-- toc from https://github.com/slotThe/slotThe.github.io
getTocCtx :: Context a -> Compiler (Context a)
getTocCtx ctx = do
  noToc <- (Just "true" ==) <$> (getUnderlying >>= (`getMetadataField` "no-toc"))
  writerOpts <- mkTocWriter defaultHakyllWriterOptions
  toc <- renderPandocWith chaoDocRead writerOpts =<< getResourceBody
  pure $
    mconcat
      [ ctx,
        constField "toc" $ killLinkIds (itemBody toc),
        if noToc then boolField "no-toc" (pure noToc) else mempty
      ]
  where
    mkTocWriter :: WriterOptions -> Compiler WriterOptions
    mkTocWriter writerOpts = do
      tmpl <- either (const Nothing) Just <$> unsafeCompiler (compileTemplate "" "$toc$")
      pure $
        writerOpts
          { writerTableOfContents = True,
            writerTOCDepth = 2,
            writerTemplate = tmpl,
            writerHTMLMathMethod = MathJax ""
          }

    asTxt :: (T.Text -> T.Text) -> String -> String
    asTxt f = T.unpack . f . T.pack

    killLinkIds :: String -> String
    killLinkIds = asTxt (mconcat . go . T.splitOn "id=\"toc-")
      where
        go :: [T.Text] -> [T.Text]
        go = \case
          [] -> []
          x : xs -> x : map (T.drop 1 . T.dropWhile (/= '\"')) xs

-- katexFilter :: Item String -> Compiler (Item String)
-- katexFilter = withItemBody (unixFilter "./katex_cli" [])
