content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TemplateHaskell #-}
  {-# LANGUAGE MultiWayIf #-}
  {-# LANGUAGE NamedFieldPuns #-}
  
  module Hledger.Cli.Commands.Import (
    importmode
   ,importcmd
  )
  where
  
  import Control.Monad
  import Data.List
  import Data.Text.IO qualified as T
  import System.Console.CmdArgs.Explicit
  import Text.Printf
  
  import Hledger
  import Hledger.Cli.CliOptions
  import Hledger.Cli.Commands.Add (journalAddTransaction)
  import System.IO (stderr)
  import System.FilePath (takeFileName)
  
  importmode = hledgerCommandMode
    $(embedFileRelative "Hledger/Cli/Commands/Import.txt")
    [flagNone ["catchup"] (setboolopt "catchup") "just mark all transactions as already imported"
    ,flagNone ["dry-run"] (setboolopt "dry-run") "just show the transactions to be imported"
    ]
    cligeneralflagsgroups1
    hiddenflags
    ([], Just $ argsFlag "[-f JOURNALFILE] DATAFILES...")
  
  importcmd opts@CliOpts{rawopts_=rawopts,inputopts_=iopts} j = do
    -- XXX could be helpful to show the last-seen date, and number of old transactions, too
    let
      inputfiles = listofstringopt "args" rawopts
      inputstr = intercalate ", " $ map (quoteIfNeeded.takeFileName) inputfiles
      catchup = boolopt "catchup" rawopts
      dryrun = boolopt "dry-run" rawopts
      combinedStyles = 
        let
          maybeInputStyles = commodity_styles_ . balancingopts_ $ iopts
          inferredStyles =  journalCommodityStyles j
        in
          case maybeInputStyles of
            Nothing -> Just inferredStyles
            Just inputStyles -> Just $ inputStyles <> inferredStyles
  
      iopts' = iopts{
        new_=True,  -- read only new transactions since last time
        new_save_=False,  -- defer saving .latest files until the end
        strict_=False,  -- defer strict checks until the end
        balancingopts_=defbalancingopts{commodity_styles_= combinedStyles}  -- use amount styles from both when balancing txns
        }
  
    case inputfiles of
      [] -> error' "please provide one or more data files as arguments"  -- PARTIAL:
      fs -> do
        enewjandlatestdatesforfiles <- runExceptT $ readJournalFilesAndLatestDates iopts' fs
        case enewjandlatestdatesforfiles of
          Left err -> error' err
          Right (newj, latestdatesforfiles) ->
            case sortOn tdate $ jtxns newj of
              [] -> hPrintf stderr "no new transactions found in %s\n" inputstr
  
              newts | catchup ->
                if dryrun
                  then hPrintf stderr "would skip %d new transactions (dry run)\n\n" (length newts)
                  else do
                    hPrintf stderr "marked %s as caught up, skipping %d transactions\n\n" inputstr (length newts)
                    saveLatestDatesForFiles latestdatesforfiles
  
              newts -> do
                if dryrun
                then do
                  -- show txns to be imported
                  hPrintf stderr "would import %d new transactions from %s:\n\n" (length newts) inputstr
                  mapM_ (T.putStr . showTransaction) newts
  
                  -- then check the whole journal with them added, if in strict mode
                  when (strict_ iopts) $ strictChecks
  
                else do
                  -- first check the whole journal with them added, if in strict mode
                  when (strict_ iopts) $ strictChecks
  
                  -- then append the transactions to the main journal file.
                  -- XXX This writes unix line endings (\n), some at least,
                  -- even if the file uses dos line endings (\r\n), which could leave
                  -- mixed line endings in the file. See also writeFileWithBackupIfChanged.
                  foldM_ (`journalAddTransaction` opts) j newts  -- gets forced somehow.. (how ?)
  
                  hPrintf stderr "imported %d new transactions from %s to %s\n" (length newts) inputstr (journalFilePath j)
  
                  -- and if we got this far, update each file's .latest file
                  saveLatestDatesForFiles latestdatesforfiles
  
                where
                  -- add the new transactions to the journal in memory and check the whole thing
                  strictChecks = either fail pure $ journalStrictChecks j'
                    where j' = foldl' (flip addTransaction) j newts
  