content: module Main where
  
  import App (runProgram)
  import Common
  import qualified Data.Maybe as M
  import Options.Applicative
  import Types (Options(Options))
  import Unused.CLI (SearchRunner(..))
  import Unused.Grouping (CurrentGrouping(..))
  import Unused.TermSearch (SearchBackend(..))
  import Unused.Types (RemovalLikelihood(..))
  import Unused.Util (stringToInt)
  
  main :: IO ()
  main = runProgram =<< parseCLI
  
  parseCLI :: IO Options
  parseCLI = execParser (withInfo parseOptions pHeader pDescription pFooter)
    where
      pHeader = "Unused: Analyze potentially unused code"
      pDescription =
          "Unused allows a developer to leverage an existing tags file \
                     \(located at .git/tags, tags, or tmp/tags) to identify tokens \
                     \in a codebase that are unused."
      pFooter = "CLI USAGE: $ unused"
  
  withInfo :: Parser a -> String -> String -> String -> ParserInfo a
  withInfo opts h d f = info (helper <*> opts) $ header h <> progDesc d <> footer f
  
  parseOptions :: Parser Options
  parseOptions =
      Options <$> parseSearchRunner <*> parseDisplaySingleOccurrenceMatches <*> parseLikelihoods <*>
      parseAllLikelihoods <*>
      parseIgnorePaths <*>
      parseGroupings <*>
      parseWithoutCache <*>
      parseFromStdIn <*>
      parseCommitCount <*>
      parseSearchBackend
  
  parseSearchRunner :: Parser SearchRunner
  parseSearchRunner =
      flag SearchWithProgress SearchWithoutProgress $
      short 'P' <> long "no-progress" <> help "Don't display progress during analysis"
  
  parseDisplaySingleOccurrenceMatches :: Parser Bool
  parseDisplaySingleOccurrenceMatches =
      switch $ short 's' <> long "single-occurrence" <> help "Display only single occurrences"
  
  parseLikelihoods :: Parser [RemovalLikelihood]
  parseLikelihoods = many (parseLikelihood <$> parseLikelihoodOption)
  
  parseLikelihood :: String -> RemovalLikelihood
  parseLikelihood "high" = High
  parseLikelihood "medium" = Medium
  parseLikelihood "low" = Low
  parseLikelihood _ = Unknown
  
  parseLikelihoodOption :: Parser String
  parseLikelihoodOption =
      strOption $
      short 'l' <> long "likelihood" <>
      help "[Allows multiple] [Allowed: high, medium, low] Display results based on likelihood"
  
  parseAllLikelihoods :: Parser Bool
  parseAllLikelihoods = switch $ short 'a' <> long "all-likelihoods" <> help "Display all likelihoods"
  
  parseIgnorePaths :: Parser [String]
  parseIgnorePaths =
      many $
      strOption $
      long "ignore" <> metavar "PATH" <> help "[Allows multiple] Ignore paths that contain PATH"
  
  parseGroupings :: Parser CurrentGrouping
  parseGroupings = M.fromMaybe GroupByDirectory <$> maybeGroup
    where
      maybeGroup = optional $ parseGrouping <$> parseGroupingOption
  
  parseGrouping :: String -> CurrentGrouping
  parseGrouping "directory" = GroupByDirectory
  parseGrouping "term" = GroupByTerm
  parseGrouping "file" = GroupByFile
  parseGrouping "none" = NoGroup
  parseGrouping _ = NoGroup
  
  parseGroupingOption :: Parser String
  parseGroupingOption =
      strOption $
      short 'g' <> long "group-by" <> help "[Allowed: directory, term, file, none] Group results"
  
  parseWithoutCache :: Parser Bool
  parseWithoutCache =
      switch $ short 'C' <> long "no-cache" <> help "Ignore cache when performing calculations"
  
  parseFromStdIn :: Parser Bool
  parseFromStdIn = switch $ long "stdin" <> help "Read tags from STDIN"
  
  parseCommitCount :: Parser (Maybe Int)
  parseCommitCount = (stringToInt =<<) <$> commitParser
    where
      commitParser =
          optional $
          strOption $ long "commits" <> help "Number of recent commit SHAs to display per token"
  
  parseSearchBackend :: Parser SearchBackend
  parseSearchBackend = M.fromMaybe Ag <$> maybeBackend
    where
      maybeBackend = optional $ parseBackend <$> parseBackendOption
      parseBackendOption =
          strOption $ long "search" <> help "[Allowed: ag, rg] Select searching backend"
  
  parseBackend :: String -> SearchBackend
  parseBackend "ag" = Ag
  parseBackend "rg" = Rg
  parseBackend _ = Ag
  