module Gargantext.Components.Login.Form where

import Prelude (Unit, bind, discard, notEq, pure, show, ($), (&&), (*>), (<>))
import Data.Either (Either(..))
import DOM.Simple.Event as DE
import Effect (Effect)
import Effect.Aff (launchAff_)
import Effect.Class (liftEffect)
import Formula as F
import Reactix as R
import Reactix.SyntheticEvent as E
import Reactix.DOM.HTML as H
import Toestand as T
import Toestand (useFocusedFields)

import Gargantext.Components.Login.Types (AuthRequest(..))
import Gargantext.Components.Forms (clearfix, formGroup)
import Gargantext.Ends (Backend)
import Gargantext.Sessions as Sessions
import Gargantext.Sessions (Sessions, postAuthRequest)
import Gargantext.Utils (csrfMiddlewareToken)
import Gargantext.Utils.Reactix as R2

here :: R2.Here
here = R2.here "Gargantext.Components.Login.Form"

type Form =
  { error    :: String
  , username :: String
  , password :: String
  , agreed   :: Boolean
  }

emptyForm :: Form
emptyForm = { error: "", username: "", password: "", agreed: false }

type Boxes =
  { error    :: T.Box String
  , username :: T.Box String
  , password :: T.Box String
  , agreed   :: T.Box Boolean }

formBoxes :: T.Box Form -> R.Hooks Boxes
formBoxes box = useFocusedFields box {}

type Props s v =
  ( backend  :: Backend
  , sessions :: s
  , visible  :: v
  )

form :: forall s v. T.ReadWrite s Sessions => T.ReadWrite v Boolean
     => Record (Props s v) -> R.Element
form props = R.createElement formCpt props []
formCpt :: forall s v. T.ReadWrite s Sessions => T.ReadWrite v Boolean
        => R.Component (Props s v)
formCpt = here.component "form" cpt where
  cpt props@{ backend, sessions, visible } _ = do
    cell    <- T.useBox emptyForm
    cursors <- useFocusedFields cell {}
    pure $ R2.row
      [ H.form { className: "col-md-12" }
        [ formLoginLink backend
        , requestAccessLink
        , csrfTokenInput
        , formGroup
          [ H.p {} [ F.viewText { text: cursors.error } ]
          , usernameInput cursors.username ]
        , formGroup
          [ passwordInput cursors.password
          , clearfix ]
        , termsCheckbox cursors.agreed
        , submitButton { backend, sessions, visible, cell }
        ]]

-- might be wrong, all we care about is preventDefault
type ChangeEvent = R.SyntheticEvent DE.MouseEvent

formLoginLink :: Backend -> R.Element
formLoginLink backend =
  H.h4 { className: "text-center" } {-className: "text-muted"-}
  [ H.text $ "Login to garg://" <> show backend ]

type SubmitButtonProps s v = ( cell :: T.Box Form | Props s v )

submitButton
  :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
  => R2.Leaf (SubmitButtonProps s v)
submitButton props = R.createElement submitButtonCpt props []

submitButtonCpt
  :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
  => R.Component (SubmitButtonProps s v)
submitButtonCpt = here.component "submitButton" cpt where
  cpt { backend, sessions, visible, cell } _ = do
    { agreed, username, password } <- T.useLive T.unequal cell
    pure $ 
      if agreed && (username `notEq` "") && (password `notEq` "")
      then H.div { className: "text-center" }
           [ loginSubmit $ submitForm { backend, sessions, visible } cell ]
      else H.div {} []
    
-- Attempts to submit the form
submitForm :: forall s v. T.ReadWrite s Sessions => T.Write v Boolean
           => Record (Props s v) -> T.Box Form -> ChangeEvent -> Effect Unit
submitForm { backend, sessions, visible } cell e = do
  E.preventDefault e
  state <- T.read cell
  launchAff_ $ do
    res <- postAuthRequest backend (req state)
    case res of
      Left message -> liftEffect $ T.write (state { error = message }) cell
      Right sess ->
        liftEffect $
          Sessions.change (Sessions.Login sess) sessions
          *> T.write false visible
          *> T.write (state { error = "" }) cell
    where
      req { username, password } = AuthRequest { username, password }

csrfTokenInput :: R.Element -- TODO hard-coded CSRF token
csrfTokenInput = H.input { type: "hidden", name, value } where
  name = "csrfmiddlewaretoken"
  value = csrfMiddlewareToken

termsCheckbox :: forall cell. T.ReadWrite cell Boolean => cell -> R.Element
termsCheckbox checked =
  H.div { className: "form-group form-check text-center" }
  [ F.bindCheckbox { checked, className: "form-check-input" }
  , H.label { className: "form-check-label" }
    [ H.text "I hereby accept the "
    , H.a { target: "_blank", href: termsUrl }
      [ H.text "terms of use" ] ]]
  where termsUrl = "http://gitlab.iscpif.fr/humanities/tofu/tree/master"

requestAccessLink :: R.Element
requestAccessLink =
  H.div { className: "text-center" }
  [ H.a { href, target: "_blank" } [ H.text "request access" ] ]
  where href = "https://iscpif.fr/apply-for-a-services-account/"

usernameInput :: forall cell. T.ReadWrite cell String => cell -> R.Element
usernameInput value =
  F.bindInput
  { value
  , type: "text",         className:   "form-control"
  , id:   "id_username",  placeholder: "username"
  , name: "username",     maxLength:   "254"
  }

passwordInput :: forall cell. T.ReadWrite cell String => cell -> R.Element
passwordInput value =
  F.bindInput
  { value
  , type: "password",     className:   "form-control"
  , name: "password",     placeholder: "password"
  , id:   "id_password"
  }

loginSubmit :: (ChangeEvent -> Effect Unit) -> R.Element
loginSubmit click =
  H.button { id, className, type: "submit", on: { click } }
  [ H.text "Login" ] where
    id = "login-button"
    className = "btn btn-primary btn-rounded"