module Tintin
  ( runApp
  , publish
  )
where

import Tintin.Core

require Tintin.Capabilities.Logging
require Tintin.Capabilities.Filesystem
require Tintin.Capabilities.Process
require Tintin.Parse
require Tintin.Render
require Tintin.Errors
require Tintin.ConfigurationLoading
require Tintin.Domain.HtmlFile

require Data.Text



publish :: ( Has Logging.Capability eff
           , Has Filesystem.Capability eff
           , Has Process.Capability eff
           )
        => OutputDirectory
        -> Effectful eff ()
publish (OutputDirectory p)= do
  gitContents <- Filesystem.readFile ( Filesystem.Path ".git/config" )
  let r = lines gitContents
          &  dropWhile (not . Text.isInfixOf "origin")
          &  nonEmpty
          & fmap tail
          & flatMap safeHead
          & fmap (Text.dropWhile (/= '='))
          & fmap (Text.dropWhile (/= 'g'))
  case r of
    Nothing ->
      Errors.textDie ["Could not read origin remote. Are you in a Git repository?"]

    Just remote -> do
      Logging.debug "Initializing repo"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git init"
                   )
      Logging.debug "Adding origin remote"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git remote add origin " <> remote
                   )
      Logging.debug "Cheking out gh-pages"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git checkout -b gh-pages"
                   )
      Logging.debug "Adding new docs"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git add *"
                   )
      Logging.debug "Commiting"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git commit -m 'Update docs'"
                   )
      Logging.debug "Pushing"
      Process.call ( Process.CommandName $ "cd " <> p
                     <> " && git push -f origin gh-pages"
                   )


runApp :: ( Has Logging.Capability eff
          , Has Filesystem.Capability eff
          , Has Process.Capability eff
          )
       => Bool
       -> OutputDirectory
       -> Effectful eff ()
runApp shouldUseCabal outputDirectory = do
  cleanUp outputDirectory
  docDir    <- getDocumentationDirectory
  filenames <- getDocumentationFilenames docDir
  let buildTool = if shouldUseCabal then HtmlFile.Cabal else HtmlFile.Stack

  Parse.docs docDir filenames
   & flatMap (Render.perform buildTool)
   & flatMap (ConfigurationLoading.loadInfo)
   & flatMap (Render.writeOutput outputDirectory)


cleanUp :: ( Has Logging.Capability eff
           , Has Filesystem.Capability eff
           )
        => OutputDirectory
        -> Effectful eff ()
cleanUp (OutputDirectory p) = do
  Logging.debug "Cleaning output directory"
  Filesystem.deleteIfExists (Filesystem.Path p)



getDocumentationFilenames :: ( Has Logging.Capability eff
                             , Has Filesystem.Capability eff
                             )
                          => DocumentationDirectory
                          -> Effectful eff [Filesystem.Path]
getDocumentationFilenames (DocumentationDirectory docDir) = do
  Logging.debug ( "Reading documentation files at " <> docDir )
  Filesystem.Path docDir
   & Filesystem.list
   & fmap (Filesystem.getPathsWith $ Filesystem.Extension ".md")



getDocumentationDirectory :: Has Filesystem.Capability eff
                          => Effectful eff DocumentationDirectory
getDocumentationDirectory = do
  Filesystem.Path currentDir <- Filesystem.currentDirectory
  return ( DocumentationDirectory $ currentDir <> "/doc/" )