module Gargantext.Components.Nodes.Annuaire where

import Prelude (bind, const, identity, pure, show, ($), (<$>), (<>))
import Data.Argonaut (class DecodeJson, decodeJson, (.:), (.:?))
import Data.Array as A
import Data.Maybe (Maybe(..), maybe, fromMaybe)
import Data.Sequence as Seq
import Data.Tuple (fst, snd)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff, launchAff_)
import Reactix as R
import Reactix.DOM.HTML as H

import Gargantext.Prelude

import Gargantext.Components.NgramsTable.Loader (clearCache)
import Gargantext.Components.Nodes.Annuaire.User.Contacts.Types as CT
import Gargantext.Components.Nodes.Lists.Types as NT
import Gargantext.Components.Table as T
import Gargantext.Ends (url, Frontends)
import Gargantext.Hooks.Loader (useLoader)
import Gargantext.Routes (SessionRoute(..))
import Gargantext.Routes as Routes
import Gargantext.Sessions (Session, sessionId, get)
import Gargantext.Types (NodeType(..), AffTableResult, TableResult)
import Gargantext.Utils.Reactix as R2

thisModule = "Gargantext.Components.Nodes.Annuaire"

newtype IndividuView =
  CorpusView
  { id      :: Int
  , name    :: String
  , role    :: String
  , company :: String }

--toRows :: AnnuaireTable -> Array (Maybe Contact)
--toRows (AnnuaireTable a) = a.annuaireTable

-- | Top level layout component. Loads an annuaire by id and renders
-- | the annuaire using the result
type LayoutProps = (
    frontends :: Frontends
  , nodeId :: Int
  , session :: Session
  )

annuaireLayout :: Record LayoutProps -> R.Element
annuaireLayout props = R.createElement annuaireLayoutCpt props []

annuaireLayoutCpt :: R.Component LayoutProps
annuaireLayoutCpt = R.hooksComponentWithModule thisModule "annuaireLayout" cpt
  where
    cpt { frontends, nodeId, session } _ = do
      let sid = sessionId session

      pure $ annuaireLayoutWithKey { frontends, key: show sid <> "-" <> show nodeId, nodeId, session }

type KeyLayoutProps = (
  key :: String
  | LayoutProps
  )

annuaireLayoutWithKey :: Record KeyLayoutProps -> R.Element
annuaireLayoutWithKey props = R.createElement annuaireLayoutWithKeyCpt props []

annuaireLayoutWithKeyCpt :: R.Component KeyLayoutProps
annuaireLayoutWithKeyCpt = R.hooksComponentWithModule thisModule "annuaireLayoutWithKey" cpt
  where
    cpt { frontends, nodeId, session } _ = do
      path <- R.useState' nodeId

      useLoader (fst path) (getAnnuaireInfo session) $
        \info -> annuaire { frontends, info, path, session }

type AnnuaireProps =
  ( session   :: Session
  , path      :: R.State Int
  , info      :: AnnuaireInfo
  , frontends :: Frontends
  )

-- | Renders a basic table and the page loader
annuaire :: Record AnnuaireProps -> R.Element
annuaire props = R.createElement annuaireCpt props []

-- Abuses closure to work around the Loader
annuaireCpt :: R.Component AnnuaireProps
annuaireCpt = R.hooksComponentWithModule thisModule "annuaire" cpt
  where
    cpt {session, path, info: info@(AnnuaireInfo {name, date: date'}), frontends} _ = do
      pagePath <- R.useState' $ initialPagePath (fst path)

      cacheState <- R.useState' NT.CacheOff

      pure $ R.fragment
        [ T.tableHeaderLayout { afterCacheStateChange: \_ -> launchAff_ $ clearCache unit
                              , cacheState
                              , date
                              , desc: name
                              , key: "annuaire-" <> (show $ fst cacheState)
                              , query: ""
                              , title: name
                              , user: "" }
          , H.p {} []
          , H.div {className: "col-md-3"}
            [ H.text "    Filter ", H.input { className: "form-control", style } ]
          , H.br {}
          , pageLayout { info, session, pagePath, frontends} ]
      where
        date = "Last update: " <> date'
        style = {width: "250px", display: "inline-block"}
        initialPagePath nodeId = {nodeId, params: T.initialParams}

type PagePath = { nodeId :: Int
                , params :: T.Params
                }

type PageLayoutProps =
  ( session      :: Session
  , frontends    :: Frontends
  , info         :: AnnuaireInfo
  , pagePath     :: R.State PagePath
  )

pageLayout :: Record PageLayoutProps -> R.Element
pageLayout props = R.createElement pageLayoutCpt props []

pageLayoutCpt :: R.Component PageLayoutProps
pageLayoutCpt = R.hooksComponentWithModule thisModule "pageLayout" cpt
  where
    cpt {info, frontends, pagePath, session} _ = do
      useLoader (fst pagePath) (loadPage session) $
        \table -> page {session, table, frontends, pagePath}

type PageProps = 
  ( session :: Session
  , frontends :: Frontends
  , pagePath :: R.State PagePath
  -- , info :: AnnuaireInfo
  , table :: TableResult CT.NodeContact
  )

page :: Record PageProps -> R.Element
page props = R.createElement pageCpt props []

pageCpt :: R.Component PageProps
pageCpt = R.hooksComponentWithModule thisModule "page" cpt
  where
    cpt { session, pagePath, frontends
        , table: ({count: totalRecords, docs})} _ = do
      pure $ T.table { rows, params, container, colNames, totalRecords, wrapColElts }
      where
        path = fst pagePath
        rows = (\c -> {
                   row: contactCells { annuaireId: (fst pagePath).nodeId
                                     , frontends
                                     , contact: c
                                     , session }
                   , delete: false }) <$> Seq.fromFoldable docs
        container = T.defaultContainer { title: "Annuaire" } -- TODO
        colNames = T.ColumnName <$> [ "", "First Name", "Last Name", "Company", "Lab", "Role"]
        wrapColElts = const identity
        setParams f = snd pagePath $ \pp@{params: ps} ->
          pp {params = f ps}
        params = (fst pagePath).params /\ setParams

type AnnuaireId = Int

type ContactCellsProps =
  ( annuaireId :: AnnuaireId
  , contact    :: CT.NodeContact
  , frontends  :: Frontends
  , session   :: Session
  )

contactCells :: Record ContactCellsProps -> R.Element
contactCells p = R.createElement contactCellsCpt p []

contactCellsCpt :: R.Component ContactCellsProps
contactCellsCpt = R.hooksComponentWithModule thisModule "contactCells" cpt
  where
    cpt { annuaireId
        , contact: (CT.NodeContact { id, hyperdata: (CT.HyperdataContact {who : Nothing}) })
        , frontends
        , session } _ =
      pure $ T.makeRow [ H.text ""
                       , H.span {} [ H.text "Name" ]
                       --, H.a { href, target: "blank" } [ H.text $ fromMaybe "name" contact.title ]
                       , H.text "No ContactWhere"
                       , H.text "No ContactWhereDept"
                       , H.div { className: "nooverflow"}
                               [ H.text "No ContactWhereRole" ]
                       ]
    cpt { annuaireId
        , contact: (CT.NodeContact { id
                               , hyperdata: ( CT.HyperdataContact { who : Just (CT.ContactWho { firstName
                                                                                              , lastName
                                                                                              }
                                                                               )
                                                                  }
                                            )
                               }
                   )
        , frontends
        , session } _ = do

        pure $ T.makeRow [
          H.text ""
          , H.text $ fromMaybe "First Name" firstName
          , H.text $ fromMaybe "First Name" lastName
          , H.text  "CNRS"
          -- , H.a { href } [ H.text $ fromMaybe "name" contact.title ]
            --, H.a { href, target: "blank" } [ H.text $ fromMaybe "name" contact.title ]
          --, H.text $ maybe "No ContactWhere" contactWhereOrg  (A.head $ ou)
         -- , H.text $ maybe "No ContactWhereDept" contactWhereDept (A.head $ ou)
         -- , H.div {className: "nooverflow"} [
         --     H.text $ maybe "No ContactWhereRole" contactWhereRole (A.head $ ou)
            ]
          where
            --nodepath = NodePath (sessionId session) NodeContact (Just id)
            nodepath = Routes.ContactPage (sessionId session) annuaireId id
            href = url frontends nodepath

            contactWhereOrg (CT.ContactWhere { organization: [] }) = "No Organization"
            contactWhereOrg (CT.ContactWhere { organization: orga }) =
              fromMaybe "No orga (list)" (A.head orga)
            contactWhereDept (CT.ContactWhere { labTeamDepts : [] }) = "Empty Dept"
            contactWhereDept (CT.ContactWhere { labTeamDepts : dept }) =
              fromMaybe "No Dept (list)" (A.head dept)
            contactWhereRole (CT.ContactWhere { role: Nothing }) = "Empty Role"
            contactWhereRole (CT.ContactWhere { role: Just role }) = role


data HyperdataAnnuaire = HyperdataAnnuaire
  { title :: Maybe String
  , desc  :: Maybe String }

instance decodeHyperdataAnnuaire :: DecodeJson HyperdataAnnuaire where
  decodeJson json = do
    obj   <- decodeJson json
    title <- obj .:? "title"
    desc  <- obj .:? "desc"
    pure $ HyperdataAnnuaire { title, desc }

------------------------------------------------------------------------------
newtype AnnuaireInfo = AnnuaireInfo { id        :: Int
                                    , typename  :: Int
                                    , userId    :: Int
                                    , parentId  :: Int
                                    , name      :: String
                                    , date      :: String
                                    , hyperdata :: HyperdataAnnuaire
                                    }

instance decodeAnnuaireInfo :: DecodeJson AnnuaireInfo where
  decodeJson json = do
    obj <- decodeJson json
    id        <- obj .: "id"
    typename  <- obj .: "typename"
    userId    <- obj .: "userId"
    parentId  <- obj .: "parentId"
    name      <- obj .: "name"
    date      <- obj .: "date"
    hyperdata <- obj .: "hyperdata"
    pure $ AnnuaireInfo { id : id
                        , typename : typename
                        , userId   : userId
                        , parentId : parentId
                        , name     : name
                        , date     : date
                        , hyperdata: hyperdata
                        }


--newtype AnnuaireTable  = AnnuaireTable  { annuaireTable :: Array (Maybe Contact)}

--instance decodeAnnuaireTable :: DecodeJson AnnuaireTable where
--  decodeJson json = do
--    rows <- decodeJson json
--    pure $ AnnuaireTable { annuaireTable : rows}

------------------------------------------------------------------------

loadPage :: Session -> PagePath -> AffTableResult CT.NodeContact
loadPage session {nodeId, params: { offset, limit, orderBy }} =
    get session children
 -- TODO orderBy
 -- where
 --   convOrderBy (T.ASC  (T.ColumnName "Name")) = NameAsc
 --   convOrderBy (T.DESC (T.ColumnName "Name")) = NameDesc
 --   ...
 --   convOrderBy _ = NameAsc -- TODO

  where
    children = Children NodeContact offset limit Nothing {-(convOrderBy <$> orderBy)-} (Just nodeId)

getAnnuaireInfo :: Session -> Int -> Aff AnnuaireInfo
getAnnuaireInfo session id = get session (NodeAPI Node (Just id) "")