module Gargantext.Components.MarkdownEditor where

import Data.Either (either, Either(..))
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable, null, toMaybe)
import Data.Tuple (fst)
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log2)
import DOM.Simple.Types (Element)
import Effect (Effect)
import FFI.Simple ((.=), delay)
import Prelude (($), (>>>), Unit, bind, const, discard, identity, pure, unit)
import Reactix as R
import Reactix.DOM.HTML as H
import Text.Markdown.SlamDown.Parser (parseMd)
import Text.Markdown.SlamDown.Smolder as MD
import Text.Markdown.SlamDown.Syntax (SlamDownP(..))
import Text.Smolder.Renderer.String (render)

import Gargantext.Utils.Reactix as R2

type Props =
  ( md :: String
  , nodeId :: Int
  )

compileMd' :: forall e. MD.ToMarkupOptions e -> String -> String
compileMd' options input =
  either identity (MD.toMarkup' options >>> render)
  (parseMd input :: Either String (SlamDownP String))

compileMd :: String -> String
compileMd = compileMd' MD.defaultToMarkupOptions

markdownEditor :: Record Props -> R.Element
markdownEditor p = R.createElement markdownEditorCpt p []

markdownEditorCpt :: R.Component Props
markdownEditorCpt = R.hooksComponent "G.C.MarkdownEditor" cpt
  where
    cpt {md, nodeId} _ = do
      ref <- R.useRef null
      editedMd <- R.useState' md

      -- Note: delay is necessary here, otherwise initially the HTML won't get
      -- rendered (mDiv is still null)
      R.useEffect $ delay unit $ \_ -> do
        let mDiv = toMaybe $ R.readRef ref
        case mDiv of
          Nothing -> pure $ pure unit
          Just d -> do
            _ <- pure $ (d .= "innerHTML") $ compileMd $ fst editedMd
            pure $ pure unit

      pure $ H.div { className: "markdown-editor" }
                   [ H.div { className: "row"}
                     [ H.div { className: "col-md-5" } [ H.div { ref, className: "html" } []]
                     , H.div { className: "col-md-5" }
                             [ H.div { className: "md" }
                              [ H.textarea { className: "form-control"
                                           , rows: 10
                                           , on: {change: onChange ref editedMd}
                                           } [ H.text $ fst editedMd ]
                              ]
                             ]
                     ]
                   ]

    onChange :: forall e. R.Ref (Nullable Element) -> R.State String -> e -> Effect Unit
    onChange ref (_ /\ setEditedMd) e = do
      setEditedMd $ const value
      where
        value = R2.unsafeEventValue e