module Gargantext.Hooks.Loader where

import Gargantext.Prelude
import Data.Maybe (Maybe(..), isNothing, maybe, maybe')
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Reactix as R
import Gargantext.Utils.Reactix as R2
import Gargantext.Components.LoadingSpinner (loadingSpinner)

useAff :: forall st. Aff st -> R.Hooks (Maybe st)
useAff loader = do
  (loaded /\ setLoaded) <- R.useState' Nothing
  R.useEffect1 loader $ do
    if isNothing loaded then
      R2.affEffect "G.H.Loader.useAff" $
        loader >>= (liftEffect <<< setLoaded <<< const <<< Just)
    else pure R.nothing
  pure loaded

useLoader :: forall path st. path -> (path -> Aff st) -> (st -> R.Element) -> R.Hooks R.Element
useLoader path loader render
  =   maybe' (\_ -> loadingSpinner {}) render
  <$> (useAff =<< R.useMemo2 path loader (\_ -> loader path))

useLoader2 :: forall path st. R.State path -> (path -> Aff st) -> (st -> R.Element) -> R.Hooks R.Element
useLoader2 path loader render = do
  state <- R.useState' Nothing
  useLoaderEffect2 path state loader
  pure $ maybe (loadingSpinner {}) render (fst state)
  
useLoaderEffect :: forall state. Aff state -> R.State (Maybe state) -> R.Hooks Unit
useLoaderEffect loader (state /\ setState) = do
  R.useEffect2 state loader $ do
    if isNothing state then
      R2.affEffect "G.H.Loader.useLoader" $ loader >>= (liftEffect <<< setState <<< const <<< Just)
    else pure R.nothing

useLoaderEffect' :: forall state. Aff state -> R.Hooks (R.State (Maybe state))
useLoaderEffect' aff = do
  state <- R.useState' Nothing
  useLoaderEffect aff state
  pure state

useLoaderEffect2 :: forall st path. R.State path -> R.State (Maybe st) -> (path -> Aff st) -> R.Hooks Unit
useLoaderEffect2 path state loader = do
  aff <- useRepointer path loader
  useLoaderEffect aff state

useRepointer :: forall path st. R.State path -> (path -> Aff st) -> R.Hooks (Aff st)
useRepointer path@(path' /\ _) loader = R.useMemo2 loader path' (\_ -> loader path')