module Gargantext.Components.Forest.Tree.Node.ProgressBar where

import Gargantext.Prelude

import Data.Int (fromNumber)
import Data.Maybe (Maybe(..), fromJust)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Class (liftEffect)
import Effect.Timer (clearInterval, setInterval)
import Gargantext.Components.Forest.Tree.Node.Action (ID)
import Gargantext.Routes (SessionRoute(..))
import Gargantext.Sessions (Session, get)
import Gargantext.Types as GT
import Partial.Unsafe (unsafePartial)

import Reactix as R
import Reactix.DOM.HTML as H


type Props =
  (
    asyncTask :: GT.AsyncTaskWithType
  , corpusId  :: ID
  , onFinish  :: Unit -> Effect Unit
  , session   :: Session
  )


asyncProgressBar :: Record Props -> R.Element
asyncProgressBar p = R.createElement asyncProgressBarCpt p []

asyncProgressBarCpt :: R.Component Props
asyncProgressBarCpt = R.hooksComponent "G.C.F.T.N.asyncProgressBar" cpt
  where
    cpt props@{asyncTask: (GT.AsyncTaskWithType {task: GT.AsyncTask {id}}), corpusId, onFinish} _ = do
      (progress /\ setProgress) <- R.useState' 0.0
      intervalIdRef <- R.useRef Nothing

      R.useEffectOnce' $ do
        intervalId <- setInterval 1000 $ do
          launchAff_ $ do
            asyncProgress@(GT.AsyncProgress {status}) <- queryProgress props
            liftEffect do
              setProgress \p -> min 100.0 $ GT.progressPercent asyncProgress
              if (status == GT.Finished) || (status == GT.Killed) || (status == GT.Failed) then do
                _ <- case R.readRef intervalIdRef of
                  Nothing -> pure unit
                  Just iid -> clearInterval iid
                onFinish unit
              else
                pure unit

        R.setRef intervalIdRef $ Just intervalId

        pure unit


      pure $
        H.div { className: "progress" } [
          H.div { className: "progress-bar"
                , role: "progressbar"
                , style: { width: (show $ toInt progress) <> "%" }
                } [ H.text id ]
        ]

    toInt :: Number -> Int
    toInt n = unsafePartial $ fromJust $ fromNumber n

queryProgress :: Record Props -> Aff GT.AsyncProgress
queryProgress {asyncTask: GT.AsyncTaskWithType {task: GT.AsyncTask {id}, typ}, corpusId, session} = get session p
  where
    p = NodeAPI GT.Corpus (Just corpusId) $ path <> id <> "/poll?limit=1"
    path = GT.asyncTaskTypePath typ