content: {-# LANGUAGE QuasiQuotes #-}
  
  module Hledger.Flow.Import.ImportHelpers (findInputFiles, findJournalFiles, groupIncludesUpTo, includeFileName) where
  
  import Data.Char (isDigit)
  import qualified Data.Map.Strict as Map
  import Data.Maybe (fromMaybe)
  import Hledger.Flow.Common (groupValuesBy)
  import Hledger.Flow.Import.Types (InputFileBundle)
  import Hledger.Flow.PathHelpers (AbsDir, AbsFile, RelDir, RelFile, findFilesIn, pathSize)
  import Path
  import System.FilePath (dropTrailingPathSeparator)
  
  findInputFiles :: Integer -> AbsDir -> IO [AbsFile]
  findInputFiles startYear = do
    let excludeDirs = [[reldir|2-preprocessed|], [reldir|3-journal|]] ++ commonExcludeDirs
    findFilesIn (includeYearFilesForParent [reldir|1-in|] startYear) excludeDirs
  
  findJournalFiles :: AbsDir -> IO [AbsFile]
  findJournalFiles = do
    let excludeDirs = [[reldir|1-in|], [reldir|2-preprocessed|]] ++ commonExcludeDirs
    findFilesIn (includeYearFilesForParent [reldir|3-journal|] 0) excludeDirs
  
  -- | Include only files directly underneath parentDir/yearDir, e.g. 1-in/2020/* or 3-journal/2020/*
  includeYearFilesForParent :: RelDir -> Integer -> AbsDir -> Bool
  includeYearFilesForParent parentDir startYear d =
    (dirname . parent) d == parentDir
      && length shortDirName == 4
      && all isDigit shortDirName
      && read shortDirName >= startYear
    where
      shortDirName = dirToStringNoSlash d
  
  dirToStringNoSlash :: AbsDir -> String
  dirToStringNoSlash = init . Path.toFilePath . Path.dirname
  
  commonExcludeDirs :: [RelDir]
  commonExcludeDirs = [[reldir|_manual_|], [reldir|__pycache__|]]
  
  groupIncludesUpTo :: RelDir -> [RelFile] -> InputFileBundle
  groupIncludesUpTo = groupIncludesUpTo' Map.empty
  
  groupIncludesUpTo' :: InputFileBundle -> RelDir -> [RelFile] -> InputFileBundle
  groupIncludesUpTo' acc _ [] = acc
  groupIncludesUpTo' acc stopAt journals = do
    let dirs = map parent journals :: [RelDir]
    let shouldStop = stopAt `elem` dirs
    if shouldStop
      then acc
      else do
        let grouped = groupIncludeFilesPerYear journals
        groupIncludesUpTo' (acc <> grouped) stopAt (Map.keys grouped)
  
  groupIncludeFilesPerYear :: [RelFile] -> InputFileBundle
  groupIncludeFilesPerYear [] = Map.empty
  groupIncludeFilesPerYear ps@(p : _) =
    if pathSize (parent p) == 6
      then groupValuesBy initialIncludeFilePath ps
      else groupValuesBy parentIncludeFilePath ps
  
  initialIncludeFilePath :: RelFile -> RelFile
  initialIncludeFilePath p = (parent . parent . parent) p </> includeFileName p
  
  parentIncludeFilePath :: RelFile -> RelFile
  parentIncludeFilePath p = (parent . parent) p </> filename p
  
  includeFileName :: RelFile -> RelFile
  includeFileName f = do
    let includeFile = (dropTrailingPathSeparator . toFilePath . dirname . parent) f ++ "-include.journal"
    fromMaybe [relfile|unknown-include.journal|] $ parseRelFile includeFile
  