{-# LANGUAGE FlexibleContexts, UnicodeSyntax #-}
module Villefort.Daily (dailyCheck ) where

import Villefort.Definitions (VConfig(..)
                             , Weekly(..))
import Villefort.Database (execQuery, makeQuery, addDaily)
import Control.Monad.Reader (MonadIO,MonadReader,runReaderT,forever,liftIO)
import Control.Concurrent (threadDelay)
import Villefort.Util (D
                      ,unpackStringToDate
                      ,getDay
                      ,day
                      ,month
                      ,year
                      ,getDate
                      ,getDateD)

-- | writes date to local database
writeDate :: (MonadReader VConfig m, MonadIO m) => m ()
writeDate = do
  date <- liftIO $ show <$> getDate
  execQuery ("update dates set  date = ? where type = 'date';") [date]

-- | reads date from local database
readDate :: (MonadReader VConfig m, MonadIO m) => m D
readDate = do
  rawDate <- makeQuery "select date from dates where type = 'date';"
  return $ unpackStringToDate $ head $ head $ rawDate

-- | writes day of week from local database
writeDay :: (MonadReader VConfig m, MonadIO m) => m ()
writeDay = do
  newDay <- liftIO $ show <$> getDay
  execQuery ("update dates set  date = ? where type = 'day';") [newDay]

-- | read day of week from local database
readDay :: (MonadReader VConfig m, MonadIO m) => m Int
readDay = do
  rawDay <- makeQuery "select date from dates where type = 'day';"
  let int = read (head $ head $ rawDay) :: Int
  return int


runCheck  Eq x  VConfig  D  D  (VConfig  [IO [String]])  (D  x)  String   IO ()
runCheck vconf oldDate currentDate extract extractInt addText  =
  if notrun  then
    return ()
  else do
    putStrLn addText
    todo  sequence (extract vconf)
    mapM_ add todo
    where add = (\x  if null x then return () else runReaderT (addDaily x) vconf)
          notrun = (extractInt oldDate == extractInt currentDate)

-- | Runs days of the week specific tasks
runWeekly :: VConfig -> Int -> Int -> IO ()
runWeekly conf old current = do
  if old /= current
    then do
    let stmt = selector conf (current-1)
    stmts <- sequence stmt
    mapM_ add stmts
    else putStrLn "didn't run weekly"
    where add = (\x -> if Prelude.null x then return () else runReaderT ( addDaily x) conf)

-- | selects correct tasks based on day of the week
selector :: (Num a, Eq a) => VConfig -> a -> [IO [String]]
selector  conf x
  | x == 0 = monday lookconf
  | x == 1 = tuesday lookconf
  | x == 2 = wednesday lookconf
  | x == 3 = thursday lookconf
  | x == 4 = friday lookconf
  | x == 5 = saturday lookconf
  | otherwise = sunday lookconf
    where lookconf = weekly conf

-- | Run daily check for updates
dailyCheck :: VConfig -> IO ()
dailyCheck conf = forever $ do
  currentDate <- getDateD
  currentDay  <- getDay
  oldDate <- runReaderT readDate conf
  oldDay <- runReaderT readDay conf
  let checkFunc = runCheck conf oldDate currentDate
  checkFunc daily day "added daily tasks"
  checkFunc monthly month "added monthly tasks"
  checkFunc yearly year "added yearly tasks"
  runWeekly conf oldDay currentDay
  runReaderT writeDate conf
  runReaderT writeDay conf
  -- check interval 
  threadDelay 18000000