{-|
Module      : Gargantext.Core.Utils.DateUtils
Description : 
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX
-}


module Gargantext.Core.Utils.DateUtils where

import Data.Text qualified as T
import Data.Time (UTCTime(..), fromGregorian, toGregorian, utctDay)
import Data.Time.Format (parseTimeM, defaultTimeLocale)
import Data.Time.Format.ISO8601 (iso8601ParseM)
import Data.Time.LocalTime (TimeOfDay(..), timeOfDayToTime, timeToTimeOfDay)
import Gargantext.Defaults qualified as Def
import Gargantext.Prelude
import Text.Printf (printf)


--
--readInt :: IO [Char] -> IO Int
--readInt = readLn
--
--readBool :: IO [Char] -> IO Bool
--readBool = readLn

utc2gregorian :: UTCTime -> (Integer, Int, Int)
utc2gregorian date = toGregorian $ utctDay date

gregorian2year :: (Integer, Int, Int) -> Integer
gregorian2year (y, _m, _d) = y

utc2year :: UTCTime -> Integer
utc2year date = gregorian2year $ utc2gregorian date

averageLength :: Fractional a => [[a1]] -> a
averageLength l = fromIntegral (sum (map length l)) / fromIntegral (length l)

--main :: IO ()
--main = do
--	c <- getCurrentTime
--	print c -- $ toYear $ toGregorian $ utctDay c


-- | A simplified UTCTime record for our purposes.
--   The standard 'Date.Time.Clock.UTCTime' requires 'Integer' for
--   year and separates day from time. This structure is supposed to
--   reduce the boilerplate needed for date manipulation.
data UTCTimeR =
  UTCTimeR { year   :: Int
           , month  :: Int
           , day    :: Int
           , hour   :: Int
           , minute :: Int
           , sec    :: Int }
  deriving (Show, Eq, Generic)

defUTCTimeR :: UTCTimeR
defUTCTimeR = UTCTimeR { year   = fromIntegral Def.year
                       , month  = Def.month
                       , day    = Def.day
                       , hour   = Def.hour
                       , minute = Def.minute
                       , sec    = Def.second }

toUTCTime :: UTCTimeR -> UTCTime
toUTCTime (UTCTimeR { .. }) = UTCTime dayPart timePart
  where
    dayPart = fromGregorian (fromIntegral year) month day
    timePart = timeOfDayToTime (TimeOfDay hour minute (fromIntegral sec))

toUTCTimeR :: UTCTime -> UTCTimeR
toUTCTimeR (UTCTime { .. }) = UTCTimeR { year = fromIntegral year
                                       , sec = round (realToFrac sec :: Float)
                                       , .. }
  where
    (year, month, day) = toGregorian utctDay
    TimeOfDay hour minute sec = timeToTimeOfDay utctDayTime


-- | Parse with multiple format attempts
parseFlexibleTime :: Text -> Maybe UTCTime
parseFlexibleTime t = msum
  [ iso8601ParseM s
  , parseTimeM True defaultTimeLocale "%Y-%m-%dT%H:%M:%S" s
  , parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M:%S" s
  , parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M:%S UTC" s
  , parseTimeM True defaultTimeLocale "%Y-%m-%d" s
  ]
  where
    s = T.unpack t

-- | Parse date and return date parts (list of [yyyy, mm, dd])
dateParts :: Text -> [Text]
dateParts t = [T.pack $ printf "%04d" y, T.pack $ printf "%02d" m, T.pack $ printf "%02d" d]
  where
    mParsed = parseFlexibleTime t
    parsed = fromMaybe (toUTCTime defUTCTimeR) mParsed
    (y, m, d) = toGregorian $ utctDay parsed

