{-# 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))