{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      : Git.Stale.Types.Results
-- License     : BSD3
-- Maintainer  : tbidne@gmail.com
-- Provides a `Results` type that wraps two maps, one for merged branches
-- and one for unmerged.
module Git.Stale.Types.Results
  ( Results (..),
    MergedDisp (..),
    UnMergedDisp (..),
    ResultsDisp (..),
    toResultsDisp,
    toResults,
  )
where

import qualified Data.Foldable as F
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import Git.Stale.Types.Branch
import Git.Types.GitTypes

-- | Wrapper for holding @`M.Map` `Author` [`Branch` a]@ data.
data Results
  = Results
      { -- | Holds the results for merged branches
        Results -> Map Author [Branch 'Merged]
mergedMap :: M.Map Author [Branch 'Merged],
        -- | Holds the results for unmerged branches
        Results -> Map Author [Branch 'UnMerged]
unMergedMap :: M.Map Author [Branch 'UnMerged]
      }
  deriving (Int -> Results -> ShowS
[Results] -> ShowS
Results -> String
(Int -> Results -> ShowS)
-> (Results -> String) -> ([Results] -> ShowS) -> Show Results
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Results] -> ShowS
$cshowList :: [Results] -> ShowS
show :: Results -> String
$cshow :: Results -> String
showsPrec :: Int -> Results -> ShowS
$cshowsPrec :: Int -> Results -> ShowS
Show)

-- | Newtype wrapper for merged branches over (display string, num branches).
newtype MergedDisp = MergedDisp (T.Text, Int)

-- | Newtype wrapper for unmerged branches over (display string, num branches).
newtype UnMergedDisp = UnMergedDisp (T.Text, Int)

-- | Newtype wrapper over ('MergedDisp', 'UnMergedDisp').
newtype ResultsDisp = ResultsDisp (MergedDisp, UnMergedDisp)

-- | Transforms the 'Results' into a 'ResultsDisp' for display purposes.
-- Strips out the @prefix@ from the branches, if it exists.
toResultsDisp :: T.Text -> Results -> ResultsDisp
toResultsDisp :: Text -> Results -> ResultsDisp
toResultsDisp prefix :: Text
prefix Results {Map Author [Branch 'Merged]
mergedMap :: Map Author [Branch 'Merged]
mergedMap :: Results -> Map Author [Branch 'Merged]
mergedMap, Map Author [Branch 'UnMerged]
unMergedMap :: Map Author [Branch 'UnMerged]
unMergedMap :: Results -> Map Author [Branch 'UnMerged]
unMergedMap} = (MergedDisp, UnMergedDisp) -> ResultsDisp
ResultsDisp (MergedDisp
merged, UnMergedDisp
unmerged)
  where
    merged :: MergedDisp
merged = (Text, Int) -> MergedDisp
MergedDisp ((Text, Int) -> MergedDisp) -> (Text, Int) -> MergedDisp
forall a b. (a -> b) -> a -> b
$ Text -> Map Author [Branch 'Merged] -> (Text, Int)
forall (a :: BranchStatus).
Text -> Map Author [Branch a] -> (Text, Int)
displayMap Text
prefix Map Author [Branch 'Merged]
mergedMap
    unmerged :: UnMergedDisp
unmerged = (Text, Int) -> UnMergedDisp
UnMergedDisp ((Text, Int) -> UnMergedDisp) -> (Text, Int) -> UnMergedDisp
forall a b. (a -> b) -> a -> b
$ Text -> Map Author [Branch 'UnMerged] -> (Text, Int)
forall (a :: BranchStatus).
Text -> Map Author [Branch a] -> (Text, Int)
displayMap Text
prefix Map Author [Branch 'UnMerged]
unMergedMap

displayMap :: T.Text -> M.Map Author [Branch a] -> (T.Text, Int)
displayMap :: Text -> Map Author [Branch a] -> (Text, Int)
displayMap prefix :: Text
prefix = (Author -> [Branch a] -> (Text, Int) -> (Text, Int))
-> (Text, Int) -> Map Author [Branch a] -> (Text, Int)
forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
M.foldrWithKey Author -> [Branch a] -> (Text, Int) -> (Text, Int)
forall (a :: BranchStatus).
Author -> [Branch a] -> (Text, Int) -> (Text, Int)
f ("", 0)
  where
    f :: Author -> [Branch a] -> (T.Text, Int) -> (T.Text, Int)
    f :: Author -> [Branch a] -> (Text, Int) -> (Text, Int)
f (Author k :: Text
k) ns :: [Branch a]
ns acc :: (Text, Int)
acc = case [Branch a]
ns of
      [] -> (Text, Int)
acc
      xs :: [Branch a]
xs ->
        ( Text
k
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " ("
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show ([Branch a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Branch a]
xs))
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "): "
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Branch a] -> Text
forall (a :: BranchStatus). Text -> [Branch a] -> Text
branchesToName Text
prefix [Branch a]
ns
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "\n\n"
            Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Text, Int) -> Text
forall a b. (a, b) -> a
fst (Text, Int)
acc,
          (Text, Int) -> Int
forall a b. (a, b) -> b
snd (Text, Int)
acc Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Branch a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Branch a]
xs
        )

-- | Maps [`AnyBranch`] to `Results`. Pattern matches on `AnyBranch` to reveal
-- the underlying `BranchStatus`, ensuring merged and unmerged branches are
-- organized separately.
toResults :: [AnyBranch] -> Results
toResults :: [AnyBranch] -> Results
toResults = (Results -> AnyBranch -> Results)
-> Results -> [AnyBranch] -> Results
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' Results -> AnyBranch -> Results
go Results
mkResults
  where
    go :: Results -> AnyBranch -> Results
go mp :: Results
mp (MergedBranch b :: Branch 'Merged
b@(MkBranch _ a :: Author
a _)) = Author -> Branch 'Merged -> Results -> Results
insertMerged Author
a Branch 'Merged
b Results
mp
    go mp :: Results
mp (UnMergedBranch b :: Branch 'UnMerged
b@(MkBranch _ a :: Author
a _)) = Author -> Branch 'UnMerged -> Results -> Results
insertUnMerged Author
a Branch 'UnMerged
b Results
mp

mkResults :: Results
mkResults :: Results
mkResults = Map Author [Branch 'Merged]
-> Map Author [Branch 'UnMerged] -> Results
Results Map Author [Branch 'Merged]
forall k a. Map k a
M.empty Map Author [Branch 'UnMerged]
forall k a. Map k a
M.empty

insertMerged :: Author -> Branch 'Merged -> Results -> Results
insertMerged :: Author -> Branch 'Merged -> Results -> Results
insertMerged a :: Author
a b :: Branch 'Merged
b Results {Map Author [Branch 'Merged]
mergedMap :: Map Author [Branch 'Merged]
mergedMap :: Results -> Map Author [Branch 'Merged]
mergedMap, Map Author [Branch 'UnMerged]
unMergedMap :: Map Author [Branch 'UnMerged]
unMergedMap :: Results -> Map Author [Branch 'UnMerged]
unMergedMap} = Map Author [Branch 'Merged]
-> Map Author [Branch 'UnMerged] -> Results
Results Map Author [Branch 'Merged]
mergedMap' Map Author [Branch 'UnMerged]
unMergedMap
  where
    mergedMap' :: Map Author [Branch 'Merged]
mergedMap' = case Author -> Map Author [Branch 'Merged] -> Maybe [Branch 'Merged]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Author
a Map Author [Branch 'Merged]
mergedMap of
      Nothing -> Author
-> [Branch 'Merged]
-> Map Author [Branch 'Merged]
-> Map Author [Branch 'Merged]
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Author
a [Branch 'Merged
b] Map Author [Branch 'Merged]
mergedMap
      Just bs :: [Branch 'Merged]
bs -> Author
-> [Branch 'Merged]
-> Map Author [Branch 'Merged]
-> Map Author [Branch 'Merged]
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Author
a (Branch 'Merged
b Branch 'Merged -> [Branch 'Merged] -> [Branch 'Merged]
forall a. a -> [a] -> [a]
: [Branch 'Merged]
bs) Map Author [Branch 'Merged]
mergedMap

insertUnMerged :: Author -> Branch 'UnMerged -> Results -> Results
insertUnMerged :: Author -> Branch 'UnMerged -> Results -> Results
insertUnMerged a :: Author
a b :: Branch 'UnMerged
b Results {Map Author [Branch 'Merged]
mergedMap :: Map Author [Branch 'Merged]
mergedMap :: Results -> Map Author [Branch 'Merged]
mergedMap, Map Author [Branch 'UnMerged]
unMergedMap :: Map Author [Branch 'UnMerged]
unMergedMap :: Results -> Map Author [Branch 'UnMerged]
unMergedMap} = Map Author [Branch 'Merged]
-> Map Author [Branch 'UnMerged] -> Results
Results Map Author [Branch 'Merged]
mergedMap Map Author [Branch 'UnMerged]
unMergedMap'
  where
    unMergedMap' :: Map Author [Branch 'UnMerged]
unMergedMap' = case Author -> Map Author [Branch 'UnMerged] -> Maybe [Branch 'UnMerged]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Author
a Map Author [Branch 'UnMerged]
unMergedMap of
      Nothing -> Author
-> [Branch 'UnMerged]
-> Map Author [Branch 'UnMerged]
-> Map Author [Branch 'UnMerged]
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Author
a [Branch 'UnMerged
b] Map Author [Branch 'UnMerged]
unMergedMap
      Just bs :: [Branch 'UnMerged]
bs -> Author
-> [Branch 'UnMerged]
-> Map Author [Branch 'UnMerged]
-> Map Author [Branch 'UnMerged]
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Author
a (Branch 'UnMerged
b Branch 'UnMerged -> [Branch 'UnMerged] -> [Branch 'UnMerged]
forall a. a -> [a] -> [a]
: [Branch 'UnMerged]
bs) Map Author [Branch 'UnMerged]
unMergedMap