    {-# LANGUAGE QuasiQuotes #-}

    module Hledger.Cli.Commands.Checkdupes (
      checkdupesmode
     ,checkdupes
    )
    where

    import Data.Function
    import Data.List
    import Data.String.Here
    import qualified Data.Text as T
    import Hledger
    import Hledger.Cli.CliOptions
    import System.Console.CmdArgs.Explicit
    import Text.Printf

    checkdupesmode :: Mode RawOpts
    checkdupesmode = hledgerCommandMode
      [here| check-dupes
    Reports account names having the same leaf but different prefixes.
    In other words, two or more leaves that are categorized differently.
    Reads the default journal file, or another specified as an argument.
    An example: http://stefanorodighiero.net/software/hledger-dupes.html
      |]
      []
      [generalflagsgroup1]
      []
      ([], Nothing)

    checkdupes _opts j = mapM_ render $ checkdupes' $ accountsNames j

    accountsNames :: Journal -> [(String, AccountName)]
    accountsNames j = map leafAndAccountName as
      where leafAndAccountName a = (T.unpack $ accountLeafName a, a)
            ps = journalPostings j
            as = nub $ sort $ map paccount ps

    checkdupes' :: (Ord k, Eq k) => [(k, v)] -> [(k, [v])]
    checkdupes' l = zip dupLeafs dupAccountNames
      where dupLeafs = map (fst . head) d
            dupAccountNames = map (map snd) d
            d = dupes' l
            dupes' = filter ((> 1) . length)
              . groupBy ((==) `on` fst)
              . sortBy (compare `on` fst)

    render :: (String, [AccountName]) -> IO ()
    render (leafName, accountNameL) = printf "%s as %s\n" leafName (concat $ intersperse ", " (map T.unpack accountNameL))