{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}

module Events.State.Modal.Detail
    ( updateField
    , finishSubtask
    , finishDescription
    , finishDue
    , showDetail
    , getCurrentItem
    , getCurrentMode
    , getField
    , setComplete
    , remove
    , insertMode
    , editDescription
    , editDue
    , newItem
    , nextSubtask
    , previousSubtask
    , lastSubtask
    ) where

import ClassyPrelude

import Control.Lens ((&), (.~), (^.))

import           Data.Taskell.Date       (dayToOutput)
import qualified Data.Taskell.Subtask    as ST (blank, name, toggle)
import           Data.Taskell.Task       (Task, addSubtask, countSubtasks, description, due,
                                          getSubtask, removeSubtask, setDescription, setDue,
                                          updateSubtask)
import           Events.State            (getCurrentTask, setCurrentTask)
import           Events.State.Types      (State, Stateful, mode)
import           Events.State.Types.Mode (DetailItem (..), DetailMode (..), ModalType (Detail),
                                          Mode (Modal))
import           UI.Field                (Field, blankField, getText, textToField)

updateField :: (Field -> Field) -> Stateful
updateField fieldEvent s =
    pure $
    case s ^. mode of
        Modal (Detail detailItem (DetailInsert field)) ->
            s & mode .~ Modal (Detail detailItem (DetailInsert (fieldEvent field)))
        _ -> s

finishSubtask :: Stateful
finishSubtask state = do
    text <- getText <$> getField state
    i <- getCurrentSubtask state
    task <- updateSubtask i (ST.name .~ text) <$> getCurrentTask state
    setCurrentTask task $ state & mode .~ Modal (Detail (DetailItem i) (DetailInsert blankField))

finish :: (Text -> Task -> Task) -> Stateful
finish fn state = do
    text <- getText <$> getField state
    task <- fn text <$> getCurrentTask state
    setCurrentTask task $ state & mode .~ Modal (Detail (DetailItem 0) DetailNormal)

finishDescription :: Stateful
finishDescription = finish setDescription

finishDue :: Stateful
finishDue = finish setDue

showDetail :: Stateful
showDetail s = do
    _ <- getCurrentTask s
    let i = fromMaybe 0 $ getCurrentSubtask s
    pure $ s & mode .~ Modal (Detail (DetailItem i) DetailNormal)

getCurrentSubtask :: State -> Maybe Int
getCurrentSubtask state =
    case state ^. mode of
        Modal (Detail (DetailItem i) _) -> Just i
        _                               -> Nothing

getCurrentItem :: State -> Maybe DetailItem
getCurrentItem state =
    case state ^. mode of
        Modal (Detail item _) -> Just item
        _                     -> Nothing

getCurrentMode :: State -> Maybe DetailMode
getCurrentMode state =
    case state ^. mode of
        Modal (Detail _ m) -> Just m
        _                  -> Nothing

getField :: State -> Maybe Field
getField state =
    case state ^. mode of
        Modal (Detail _ (DetailInsert f)) -> Just f
        _                                 -> Nothing

setComplete :: Stateful
setComplete state = do
    i <- getCurrentSubtask state
    task <- updateSubtask i ST.toggle <$> getCurrentTask state
    setCurrentTask task state

remove :: Stateful
remove state = do
    i <- getCurrentSubtask state
    task <- removeSubtask i <$> getCurrentTask state
    state' <- setCurrentTask task state
    setIndex state' i

insertMode :: Stateful
insertMode state = do
    i <- getCurrentSubtask state
    task <- getCurrentTask state
    n <- (^. ST.name) <$> getSubtask i task
    case state ^. mode of
        Modal (Detail (DetailItem i') _) ->
            Just (state & mode .~ Modal (Detail (DetailItem i') (DetailInsert (textToField n))))
        _ -> Nothing

editDescription :: Stateful
editDescription state = do
    summ <- (^. description) <$> getCurrentTask state
    let summ' = fromMaybe "" summ
    pure $ state & mode .~ Modal (Detail DetailDescription (DetailInsert (textToField summ')))

editDue :: Stateful
editDue state = do
    day <- (^. due) <$> getCurrentTask state
    let day' = maybe "" dayToOutput day
    pure $ state & mode .~ Modal (Detail DetailDate (DetailInsert (textToField day')))

newItem :: Stateful
newItem state = do
    task <- addSubtask ST.blank <$> getCurrentTask state
    setCurrentTask task state

-- list navigation
changeSubtask :: Int -> Stateful
changeSubtask inc state = do
    i <- (+ inc) <$> getCurrentSubtask state
    setIndex state i

nextSubtask :: Stateful
nextSubtask = changeSubtask 1

previousSubtask :: Stateful
previousSubtask = changeSubtask (-1)

lastSubtask :: Stateful
lastSubtask state = lastIndex state >>= setIndex state

lastIndex :: State -> Maybe Int
lastIndex state = (+ (-1)) . countSubtasks <$> getCurrentTask state

setIndex :: State -> Int -> Maybe State
setIndex state i = do
    lst <- lastIndex state
    m <- getCurrentMode state
    let newIndex
            | i > lst = lst
            | i < 0 = 0
            | otherwise = i
    pure $ state & mode .~ Modal (Detail (DetailItem newIndex) m)