{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

module TM.Task where

import TM.Config
import TM.Util (replaceBy, groupBy')
import Data.Aeson
import Data.List
import Data.Time
import GHC.Generics

data Task = Task { tid       :: Int
                 , text      :: String
                 , tag       :: String
                 , completed :: Bool
                 , parentId  :: Int
                 , createdAt :: UTCTime } deriving (Show, Generic)

instance FromJSON Task
instance ToJSON   Task

type Scope = [Task] -> [Task]

updateTask :: [Task] -> Int -> Task -> [Task]
updateTask tasks n task = replaceBy ((== n) . tid) task tasks

deleteTask :: [Task] -> Task -> [Task]
deleteTask tasks task = deleteBy (\_ t -> tid t == tid task) task tasks

taskScopes :: [((String, Bool), Scope)]
taskScopes = [(("full",  False), filter (not . completed)),
              (("group", True),  groupBy' tag)]

extendableTaskScopes :: [(String, String -> [Task] -> [Task])]
extendableTaskScopes = [("tag", filterByTag)]

filterByTag :: String -> [Task] -> [Task]
filterByTag "main" = id
filterByTag tagName = filter (\t -> tag t == tagName)

selectScopes :: Config -> [((String, Bool), a)] -> [a] -> [a]
selectScopes _ [] acc = acc
selectScopes c (((k,v),scope):scopes) acc =
  case find (\o -> (cname o == k) && (readFlag (cname o) c == v)) c of
    Nothing -> selectScopes c scopes acc
    Just _  -> selectScopes c scopes (scope:acc)

extendScopes :: Config -> [(String, String -> a)] -> [a] -> [a]
extendScopes _ [] acc = acc
extendScopes c ((sName,escope):escopes) acc =
  case lookupByName sName c of
    Nothing -> extendScopes c escopes acc
    Just _  -> extendScopes c escopes (escope (readValue sName c):acc)

applyScopes :: [((String, Bool), a -> a)] ->
               [(String, String -> a -> a)] -> a -> Config -> a
applyScopes scopes escopes items c =
  foldr id items (extendScopes c escopes [] ++ selectScopes c scopes [])

processTasks :: [Task] -> Config -> [Task]
processTasks = applyScopes taskScopes extendableTaskScopes
