module Gargantext.Components.GraphExplorer.Search
  ( Props, nodeSearchControl ) where

import Prelude
import Data.Sequence as Seq
import Data.Set as Set
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import Effect (Effect)
import Reactix as R
import Reactix.DOM.HTML as H
import Toestand as T

import Gargantext.Components.InputWithAutocomplete (inputWithAutocomplete)
import Gargantext.Hooks.Sigmax.Types as SigmaxT
import Gargantext.Utils (queryMatchesLabel)
import Gargantext.Utils.Reactix as R2

here :: R2.Here
here = R2.here "Gargantext.Components.GraphExplorer.Search"

type Props = (
    graph              :: SigmaxT.SGraph
  , multiSelectEnabled :: T.Box Boolean
  , selectedNodeIds    :: T.Box SigmaxT.NodeIds
  )

-- | Whether a node matches a search string
nodeMatchesSearch :: String -> Record SigmaxT.Node -> Boolean
nodeMatchesSearch s n = queryMatchesLabel s n.label

searchNodes :: String -> Seq.Seq (Record SigmaxT.Node) -> Seq.Seq (Record SigmaxT.Node)
searchNodes "" _ = Seq.empty
searchNodes s nodes = Seq.filter (nodeMatchesSearch s) nodes

nodeSearchControl :: R2.Component Props
nodeSearchControl = R.createElement sizeButtonCpt

sizeButtonCpt :: R.Component Props
sizeButtonCpt = here.component "nodeSearchControl" cpt
  where
    cpt { graph, multiSelectEnabled, selectedNodeIds } _ = do
      search <- T.useBox ""
      search' <- T.useLive T.unequal search
      multiSelectEnabled' <- T.useLive T.unequal multiSelectEnabled

      pure $ R.fragment
        [ inputWithAutocomplete { autocompleteSearch: autocompleteSearch graph
                                , classes: "mx-2"
                                , onAutocompleteClick: \s -> triggerSearch graph s multiSelectEnabled' selectedNodeIds
                                , onEnterPress: \s -> triggerSearch graph s multiSelectEnabled' selectedNodeIds
                                , state: search } []
        , H.div { className: "btn input-group-addon"
                , on: { click: \_ -> triggerSearch graph search' multiSelectEnabled' selectedNodeIds }
                }
          [ H.span { className: "fa fa-search" } [] ]
        ]

autocompleteSearch :: SigmaxT.SGraph -> String -> Array String
autocompleteSearch graph s = Seq.toUnfoldable $ (_.label) <$> searchNodes s nodes
  where
    nodes = SigmaxT.graphNodes graph

triggerSearch :: SigmaxT.SGraph
              -> String
              -> Boolean
              -> T.Box SigmaxT.NodeIds
              -> Effect Unit
triggerSearch graph search multiSelectEnabled selectedNodeIds = do
  let graphNodes = SigmaxT.graphNodes graph
  let matching = Set.fromFoldable $ (_.id) <$> searchNodes search graphNodes

  log2 "[triggerSearch] search" search

  T.modify_ (\nodes ->
    Set.union matching $ if multiSelectEnabled then nodes else SigmaxT.emptyNodeIds) selectedNodeIds