{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TemplateHaskell #-}

module Emanote.Model.Task where

import Data.Aeson qualified as Aeson
import Data.IxSet.Typed (Indexable (..), IxSet, ixFun, ixList)
import Data.IxSet.Typed qualified as Ix
import Emanote.Model.Note (Note)
import Emanote.Model.Note qualified as N
import Emanote.Route qualified as R
import Heist.Extra.Splices.Pandoc.TaskList qualified as TaskList
import Optics.Operators ((^.))
import Optics.TH (makeLenses)
import Relude
import Text.Pandoc.Builder qualified as B

data Task = Task
  { _taskRoute :: R.LMLRoute
  , -- Index of this task within the containing note. Used to sort tasks by
    -- their original order of appearance in the Markdown file.
    _taskNum :: Word
  , _taskDescription :: [B.Inline]
  , _taskChecked :: Bool
  }
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Aeson.ToJSON)

instance Ord Task where
  (<=) = (<=) `on` (_taskRoute &&& _taskNum)

type TaskIxs =
  '[ -- Route to the note containing this task
     R.LMLRoute
   ]

type IxTask = IxSet TaskIxs Task

instance Indexable TaskIxs Task where
  indices =
    ixList
      (ixFun $ one . _taskRoute)

noteTasks :: Note -> IxTask
noteTasks note =
  let taskListItems = TaskList.queryTasks $ note ^. N.noteDoc
   in Ix.fromList
        $ zip [1 ..] taskListItems
        <&> \(idx, (checked, doc)) ->
          Task (note ^. N.noteRoute) idx doc checked

makeLenses ''Task
