{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StrictData        #-}
module GitHub.Tools.PullRequestInfo where

import           Control.Monad         (join)
import           Data.Aeson            (FromJSON, ToJSON)
import qualified Data.List             as List
import           Data.Text             (Text)
import qualified Data.Text             as Text
import           Data.Time.Clock       (UTCTime, diffUTCTime)
import           GHC.Generics          (Generic)
import           Text.Html             (prettyHtml, toHtml)
import           Text.Tabular          (Header (..), Properties (..),
                                        Table (..))
import qualified Text.Tabular.AsciiArt as AsciiArt
import qualified Text.Tabular.Html     as Html


data PullRequestInfo = PullRequestInfo
  { PullRequestInfo -> Text
prRepoName    :: Text
    -- ^ The repository for which the pull request is.
  , PullRequestInfo -> Int
prNumber      :: Int
    -- ^ The assigned pull request issue number.
  , PullRequestInfo -> Text
prUser        :: Text
    -- ^ The user who proposed this PR.
  , PullRequestInfo -> Text
prBranch      :: Text
    -- ^ The branch name from which the pull request came.
  , PullRequestInfo -> UTCTime
prCreated     :: UTCTime
    -- ^ Creation time of pull request. I.e. when it was proposed.
  , PullRequestInfo -> Text
prTitle       :: Text
    -- ^ Title of pull request.
  , PullRequestInfo -> [Text]
prReviewers   :: [Text]
    -- ^ The list of pull request reviewers (assignees).
  , PullRequestInfo -> Text
prState       :: Text
    -- ^ The mergeability state of the PR (clean = it's mergeable now).
  , PullRequestInfo -> Maybe Text
prOrigin      :: Maybe Text
    -- ^ The origin repository as user/reponame string.
  , PullRequestInfo -> Bool
prTrustworthy :: Bool
    -- ^ Whether the author is an org member (True) or an outside contributor (False).
  }
  deriving (Eq PullRequestInfo
Eq PullRequestInfo
-> (PullRequestInfo -> PullRequestInfo -> Ordering)
-> (PullRequestInfo -> PullRequestInfo -> Bool)
-> (PullRequestInfo -> PullRequestInfo -> Bool)
-> (PullRequestInfo -> PullRequestInfo -> Bool)
-> (PullRequestInfo -> PullRequestInfo -> Bool)
-> (PullRequestInfo -> PullRequestInfo -> PullRequestInfo)
-> (PullRequestInfo -> PullRequestInfo -> PullRequestInfo)
-> Ord PullRequestInfo
PullRequestInfo -> PullRequestInfo -> Bool
PullRequestInfo -> PullRequestInfo -> Ordering
PullRequestInfo -> PullRequestInfo -> PullRequestInfo
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: PullRequestInfo -> PullRequestInfo -> PullRequestInfo
$cmin :: PullRequestInfo -> PullRequestInfo -> PullRequestInfo
max :: PullRequestInfo -> PullRequestInfo -> PullRequestInfo
$cmax :: PullRequestInfo -> PullRequestInfo -> PullRequestInfo
>= :: PullRequestInfo -> PullRequestInfo -> Bool
$c>= :: PullRequestInfo -> PullRequestInfo -> Bool
> :: PullRequestInfo -> PullRequestInfo -> Bool
$c> :: PullRequestInfo -> PullRequestInfo -> Bool
<= :: PullRequestInfo -> PullRequestInfo -> Bool
$c<= :: PullRequestInfo -> PullRequestInfo -> Bool
< :: PullRequestInfo -> PullRequestInfo -> Bool
$c< :: PullRequestInfo -> PullRequestInfo -> Bool
compare :: PullRequestInfo -> PullRequestInfo -> Ordering
$ccompare :: PullRequestInfo -> PullRequestInfo -> Ordering
$cp1Ord :: Eq PullRequestInfo
Ord, PullRequestInfo -> PullRequestInfo -> Bool
(PullRequestInfo -> PullRequestInfo -> Bool)
-> (PullRequestInfo -> PullRequestInfo -> Bool)
-> Eq PullRequestInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PullRequestInfo -> PullRequestInfo -> Bool
$c/= :: PullRequestInfo -> PullRequestInfo -> Bool
== :: PullRequestInfo -> PullRequestInfo -> Bool
$c== :: PullRequestInfo -> PullRequestInfo -> Bool
Eq, (forall x. PullRequestInfo -> Rep PullRequestInfo x)
-> (forall x. Rep PullRequestInfo x -> PullRequestInfo)
-> Generic PullRequestInfo
forall x. Rep PullRequestInfo x -> PullRequestInfo
forall x. PullRequestInfo -> Rep PullRequestInfo x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PullRequestInfo x -> PullRequestInfo
$cfrom :: forall x. PullRequestInfo -> Rep PullRequestInfo x
Generic, Int -> PullRequestInfo -> ShowS
[PullRequestInfo] -> ShowS
PullRequestInfo -> String
(Int -> PullRequestInfo -> ShowS)
-> (PullRequestInfo -> String)
-> ([PullRequestInfo] -> ShowS)
-> Show PullRequestInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PullRequestInfo] -> ShowS
$cshowList :: [PullRequestInfo] -> ShowS
show :: PullRequestInfo -> String
$cshow :: PullRequestInfo -> String
showsPrec :: Int -> PullRequestInfo -> ShowS
$cshowsPrec :: Int -> PullRequestInfo -> ShowS
Show)

instance ToJSON PullRequestInfo
instance FromJSON PullRequestInfo


formatPR :: Bool -> UTCTime -> [[PullRequestInfo]] -> Text
formatPR :: Bool -> UTCTime -> [[PullRequestInfo]] -> Text
formatPR Bool
False UTCTime
now = String -> Text
Text.pack (String -> Text)
-> ([[PullRequestInfo]] -> String) -> [[PullRequestInfo]] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> String)
-> (Text -> String)
-> (Text -> String)
-> Table Text Text Text
-> String
forall rh ch a.
(rh -> String)
-> (ch -> String) -> (a -> String) -> Table rh ch a -> String
AsciiArt.render Text -> String
Text.unpack Text -> String
Text.unpack Text -> String
Text.unpack (Table Text Text Text -> String)
-> ([[PullRequestInfo]] -> Table Text Text Text)
-> [[PullRequestInfo]]
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> [[PullRequestInfo]] -> Table Text Text Text
prToTable UTCTime
now
formatPR Bool
True  UTCTime
now = String -> Text
Text.pack (String -> Text)
-> ([[PullRequestInfo]] -> String) -> [[PullRequestInfo]] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Html -> String
forall html. HTML html => html -> String
prettyHtml (Html -> String)
-> ([[PullRequestInfo]] -> Html) -> [[PullRequestInfo]] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Html)
-> (Text -> Html) -> (Text -> Html) -> Table Text Text Text -> Html
forall rh ch a.
(rh -> Html)
-> (ch -> Html) -> (a -> Html) -> Table rh ch a -> Html
Html.render Text -> Html
textHtml Text -> Html
textHtml Text -> Html
textHtml (Table Text Text Text -> Html)
-> ([[PullRequestInfo]] -> Table Text Text Text)
-> [[PullRequestInfo]]
-> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> [[PullRequestInfo]] -> Table Text Text Text
prToTable UTCTime
now
  where textHtml :: Text -> Html
textHtml = String -> Html
forall a. HTML a => a -> Html
toHtml (String -> Html) -> (Text -> String) -> Text -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack


prToTable :: UTCTime -> [[PullRequestInfo]] -> Table Text Text Text
prToTable :: UTCTime -> [[PullRequestInfo]] -> Table Text Text Text
prToTable UTCTime
now [[PullRequestInfo]]
prss = Header Text -> Header Text -> [[Text]] -> Table Text Text Text
forall rh ch a. Header rh -> Header ch -> [[a]] -> Table rh ch a
Table Header Text
rowNames Header Text
columnNames [[Text]]
rows
  where
    rowNames :: Header Text
rowNames = Properties -> [Header Text] -> Header Text
forall h. Properties -> [Header h] -> Header h
Group Properties
SingleLine
      ([Header Text] -> Header Text)
-> ([[PullRequestInfo]] -> [Header Text])
-> [[PullRequestInfo]]
-> Header Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([PullRequestInfo] -> Header Text)
-> [[PullRequestInfo]] -> [Header Text]
forall a b. (a -> b) -> [a] -> [b]
map (Properties -> [Header Text] -> Header Text
forall h. Properties -> [Header h] -> Header h
Group Properties
NoLine ([Header Text] -> Header Text)
-> ([PullRequestInfo] -> [Header Text])
-> [PullRequestInfo]
-> Header Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PullRequestInfo -> Header Text)
-> [PullRequestInfo] -> [Header Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Header Text
forall h. h -> Header h
Header (Text -> Header Text)
-> (PullRequestInfo -> Text) -> PullRequestInfo -> Header Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PullRequestInfo -> Text
getRowName))
      ([[PullRequestInfo]] -> [Header Text])
-> ([[PullRequestInfo]] -> [[PullRequestInfo]])
-> [[PullRequestInfo]]
-> [Header Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([PullRequestInfo] -> Bool)
-> [[PullRequestInfo]] -> [[PullRequestInfo]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ([PullRequestInfo] -> Bool) -> [PullRequestInfo] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [PullRequestInfo] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null)
      ([[PullRequestInfo]] -> Header Text)
-> [[PullRequestInfo]] -> Header Text
forall a b. (a -> b) -> a -> b
$ [[PullRequestInfo]]
prss

    getRowName :: PullRequestInfo -> Text
getRowName PullRequestInfo
pr =
      let repo :: Text -> Text
repo Text
num = PullRequestInfo -> Text
prRepoName PullRequestInfo
pr Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
num in
      Text -> Text
repo (Text -> Text)
-> (PullRequestInfo -> Text) -> PullRequestInfo -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Text)
-> (PullRequestInfo -> String) -> PullRequestInfo -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> String)
-> (PullRequestInfo -> Int) -> PullRequestInfo -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PullRequestInfo -> Int
prNumber (PullRequestInfo -> Text) -> PullRequestInfo -> Text
forall a b. (a -> b) -> a -> b
$ PullRequestInfo
pr

    columnNames :: Header Text
columnNames =  Properties -> [Header Text] -> Header Text
forall h. Properties -> [Header h] -> Header h
Group Properties
SingleLine
      [ Text -> Header Text
forall h. h -> Header h
Header Text
"branch"
      , Text -> Header Text
forall h. h -> Header h
Header Text
"age"
      , Text -> Header Text
forall h. h -> Header h
Header Text
"title"
      , Text -> Header Text
forall h. h -> Header h
Header Text
"state"
      , Text -> Header Text
forall h. h -> Header h
Header Text
"review_status"
      ]

    rows :: [[Text]]
rows = (PullRequestInfo -> [Text]) -> [PullRequestInfo] -> [[Text]]
forall a b. (a -> b) -> [a] -> [b]
map ((((PullRequestInfo -> Text) -> Text)
 -> [PullRequestInfo -> Text] -> [Text])
-> [PullRequestInfo -> Text]
-> ((PullRequestInfo -> Text) -> Text)
-> [Text]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((PullRequestInfo -> Text) -> Text)
-> [PullRequestInfo -> Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map
      [ \PullRequestInfo
pr -> PullRequestInfo -> Text
prUser PullRequestInfo
pr Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> PullRequestInfo -> Text
prBranch PullRequestInfo
pr
      , String -> Text
Text.pack (String -> Text)
-> (PullRequestInfo -> String) -> PullRequestInfo -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"d") ShowS -> (PullRequestInfo -> String) -> PullRequestInfo -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> String)
-> (PullRequestInfo -> Int) -> PullRequestInfo -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> UTCTime -> Int
diffInDays UTCTime
now (UTCTime -> Int)
-> (PullRequestInfo -> UTCTime) -> PullRequestInfo -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PullRequestInfo -> UTCTime
prCreated
      , PullRequestInfo -> Text
prTitle
      , PullRequestInfo -> Text
prState
      , String -> Text
Text.pack (String -> Text)
-> (PullRequestInfo -> String) -> PullRequestInfo -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
"," ([String] -> String)
-> (PullRequestInfo -> [String]) -> PullRequestInfo -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> String) -> [Text] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Text -> String
Text.unpack ([Text] -> [String])
-> (PullRequestInfo -> [Text]) -> PullRequestInfo -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PullRequestInfo -> [Text]
prReviewers
      ] (((PullRequestInfo -> Text) -> Text) -> [Text])
-> (PullRequestInfo -> (PullRequestInfo -> Text) -> Text)
-> PullRequestInfo
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((PullRequestInfo -> Text) -> PullRequestInfo -> Text)
-> PullRequestInfo -> (PullRequestInfo -> Text) -> Text
forall a b c. (a -> b -> c) -> b -> a -> c
flip (PullRequestInfo -> Text) -> PullRequestInfo -> Text
forall a b. (a -> b) -> a -> b
($)) ([PullRequestInfo] -> [[Text]]) -> [PullRequestInfo] -> [[Text]]
forall a b. (a -> b) -> a -> b
$ [[PullRequestInfo]] -> [PullRequestInfo]
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join [[PullRequestInfo]]
prss


diffInDays :: UTCTime -> UTCTime -> Int
diffInDays :: UTCTime -> UTCTime -> Int
diffInDays UTCTime
a UTCTime
b = NominalDiffTime -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round (NominalDiffTime -> Int) -> NominalDiffTime -> Int
forall a b. (a -> b) -> a -> b
$ UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime UTCTime
a UTCTime
b NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Fractional a => a -> a -> a
/ (NominalDiffTime
60 NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
* NominalDiffTime
60 NominalDiffTime -> NominalDiffTime -> NominalDiffTime
forall a. Num a => a -> a -> a
* NominalDiffTime
24)