{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NamedFieldPuns     #-}
module Main (main) where


import           Data.Aeson                      (Value, eitherDecode)
import           Data.Bifunctor                  (first)
import qualified Data.ByteString                 as B (readFile)
import qualified Data.ByteString.Lazy            as BS (readFile)
import           Data.Foldable                   (for_)
import qualified Data.Text.IO                    as TIO (putStrLn)
import           Data.Yaml                       (decodeEither')

import           System.Console.CmdArgs.Implicit (Data, Typeable, argPos, args,
                                                  cmdArgs, def, help, summary,
                                                  typ, (&=))
import           System.FilePath                 (takeExtension)
import           Text.Mustache                   (automaticCompile, substitute,
                                                  toMustache)


data Arguments = Arguments
  { template     :: FilePath
  , templateDirs :: [FilePath]
  , dataFiles    :: [FilePath]
  } deriving (Show, Data, Typeable)


commandArgs :: Arguments
commandArgs = Arguments
  { template = def
      &= argPos 0
      &= typ "TEMPLATE"
  , dataFiles = def
      &= args
      &= typ "DATA-FILES"
  , templateDirs = ["."]
      &= help "The directories in which to search for the templates"
      &= typ "DIRECTORIES"
  } &= summary "Simple mustache template subtitution"


readJSON :: FilePath -> IO (Either String Value)
readJSON = fmap eitherDecode . BS.readFile


readYAML :: FilePath -> IO (Either String Value)
readYAML = fmap (first show . decodeEither') . B.readFile


main :: IO ()
main = do
  (Arguments { template, templateDirs, dataFiles }) <- cmdArgs commandArgs

  eitherTemplate <- automaticCompile templateDirs template

  case eitherTemplate of
    Left err -> print err
    Right compiledTemplate ->
      for_ dataFiles $ \file -> do

        let decoder =
              case takeExtension file of
                ".yml"  -> readYAML
                ".yaml" -> readYAML
                _       -> readJSON
        decoded <- decoder file

        either
          putStrLn
          (TIO.putStrLn . substitute compiledTemplate . toMustache)
          decoded
