content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE OverloadedStrings #-}
  module Buchhaltung.Commandline where
  
  import           Buchhaltung.AQBanking
  import           Buchhaltung.Add
  import           Buchhaltung.Common
  import           Buchhaltung.Importers
  import           Buchhaltung.Match
  import           Buchhaltung.OptionParsers
  import           Control.Arrow
  import           Control.DeepSeq
  import           Control.Exception
  import           Control.Monad.RWS.Strict
  import           Control.Monad.Reader
  import           Data.Maybe
  import qualified Data.Text as T
  import           Hledger.Data (Journal)
  import           Hledger.Read (readJournalFile)
  import           Options.Applicative
  import           System.Directory
  import           System.Environment
  import           System.FilePath
  import           System.Process
  import           Text.Printf
  
  runMain :: IO ()
  runMain = do
    opts <- evaluate . force =<<
      customExecParser (prefs showHelpOnEmpty)
      =<< mainParser
      :: IO (RawOptions ())
    let
      prog ::  ErrorT IO ()
      prog = do
          config <- liftIO $ readConfigFromFile $ oProfile opts
          run (oAction opts) =<< toFull opts config
    either (error . T.unpack) return =<< runExceptT prog
  
  -- * Running Option Parsers and Actions
  
  run :: Action -> FullOptions () -> ErrorT IO ()
  run (Add partners) options =
    void $ runRWST add options{oEnv = partners} mempty
  
  run (Import version file action) options = runImport action
    where runImport (Paypal puser) =
            importReadWrite paypalImporter (options' puser) file
          runImport NatwestIntl =
            importReadWrite natwestIntlImporter (options' ()) file
          runImport BarclaysUk =
            importReadWrite barclaysUkImporter (options' ()) file
          runImport BarclaycardUs =
            importReadWrite barclaycardusImporter (options' ()) file
          runImport (ComdirectVisa blz) =
            importReadWrite comdirectVisaImporter (options' blz) file
          runImport (Pncbank accountId) =
            importReadWrite pncbankImporter (options' accountId) file
          runImport (Revolut user) =
            importReadWrite revolutImporter (options' user) file
          runImport (Monefy settings) =
            importReadWrite monefyImporter (options' settings) file
          runImport AQBankingImport =
            importReadWrite aqbankingImporter (options' ()) file
          options' env = options{oEnv = (env, version)}
  
  run (Update version doMatch doRequest) options = do
    res <- runAQ options $ aqbankingListtrans doRequest
    void $ runRWST
      (mapM (importWrite . aqbankingImporter . Left) res)
      options{oEnv = ((), version)} ()
    when doMatch $ run Match options
  
  run (Commit hledger args) options = flip runReaderT options $ do
    un <- readUser $  show . name
    dir <- takeDirectory <&> absolute =<< readLedger mainLedger
    bal <- lift $ runAQ options $ readAqbanking ["listbal"]
    sheet <- lift $ run readProcess' ["balance", "-e", "tomorrow"] options
    liftIO $ do setCurrentDirectory dir
                callProcess "git" $ "commit":args ++
                  ["-m", intercalateL "\n" $ ["User " ++ un, ""]
                    ++ bal ++ ["Balance Sheet:", sheet]]
    where run = if hledger then runHledger else runLedger
  
  run ListBalances options = void $ runAQ options $ callAqbanking ["listbal"]
    
  run Setup options = void $ runAQ options aqbankingSetup
  
  run Match options =
    withSystemTempDirectory "dbacl" $ \tmpdir -> 
    loadJournal [Just . imported] options >>= match options{oEnv = tmpdir}
  
  run (AQBanking args) options = void $ runAQ options $ callAqbanking args
  
  run (Ledger args) options = runLedger callProcess args options
  
  run (HLedger args) options = runHledger callProcess args options
  
  runLedger run = runLedger' run cLedgerExecutable mainLedger
  runHledger run = runLedger' run cHledgerExecutable (maybe mainLedger const =<< mainHledger)
  
  runLedger' run getExec getLedger args options = flip runReaderT options $ do
    exec <- readConfig getExec
    ledger <- absolute =<< readLedger getLedger
    liftIO $ do
      setEnv "LEDGER" ledger
      run exec args
  
  