{-
   Copyright 2020 Eike K. & Contributors

   SPDX-License-Identifier: AGPL-3.0-or-later
-}


module Comp.NotificationHookManage exposing
    ( Model
    , Msg
    , init
    , update
    , view
    )

import Api
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.NotificationHook exposing (NotificationHook)
import Comp.Basic as B
import Comp.MenuBar as MB
import Comp.NotificationHookForm
import Comp.NotificationHookTable
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Http
import Messages.Comp.NotificationHookManage exposing (Texts)
import Styles as S


type alias Model =
    { listModel : Comp.NotificationHookTable.Model
    , detailModel : Maybe Comp.NotificationHookForm.Model
    , items : List NotificationHook
    , deleteConfirm : DeleteConfirm
    , loading : Bool
    , formState : FormState
    , jsonFilterError : Maybe String
    }


type DeleteConfirm
    = DeleteConfirmOff
    | DeleteConfirmOn


type SubmitType
    = SubmitDelete
    | SubmitUpdate
    | SubmitCreate


type FormState
    = FormStateInitial
    | FormErrorHttp Http.Error
    | FormSubmitSuccessful SubmitType
    | FormErrorSubmit String
    | FormErrorInvalid


type Msg
    = TableMsg Comp.NotificationHookTable.Msg
    | DetailMsg Comp.NotificationHookForm.Msg
    | GetDataResp (Result Http.Error (List NotificationHook))
    | SubmitResp SubmitType (Result Http.Error BasicResult)
    | NewHookInit
    | BackToTable
    | Submit
    | RequestDelete
    | CancelDelete
    | DeleteHookNow String
    | VerifyFilterResp NotificationHook (Result Http.Error BasicResult)


initModel : Model
initModel =
    { listModel = Comp.NotificationHookTable.init
    , detailModel = Nothing
    , items = []
    , loading = False
    , formState = FormStateInitial
    , deleteConfirm = DeleteConfirmOff
    , jsonFilterError = Nothing
    }


initCmd : Flags -> Cmd Msg
initCmd flags =
    Api.getHooks flags GetDataResp


init : Flags -> ( Model, Cmd Msg )
init flags =
    ( initModel, initCmd flags )



--- Update


update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
update flags msg model =
    case msg of
        VerifyFilterResp hook (Ok res) ->
            if res.success then
                postHook flags hook model

            else
                ( { model
                    | loading = False
                    , formState = FormErrorInvalid
                    , jsonFilterError = Just res.message
                  }
                , Cmd.none
                )

        VerifyFilterResp _ (Err err) ->
            ( { model | formState = FormErrorHttp err }
            , Cmd.none
            )

        GetDataResp (Ok res) ->
            ( { model
                | items = res
                , formState = FormStateInitial
              }
            , Cmd.none
            )

        GetDataResp (Err err) ->
            ( { model | formState = FormErrorHttp err }
            , Cmd.none
            )

        TableMsg lm ->
            let
                ( mm, action ) =
                    Comp.NotificationHookTable.update flags lm model.listModel

                ( detail, cmd ) =
                    case action of
                        Comp.NotificationHookTable.NoAction ->
                            ( Nothing, Cmd.none )

                        Comp.NotificationHookTable.EditAction hook ->
                            let
                                ( dm, dc ) =
                                    Comp.NotificationHookForm.initWith flags hook
                            in
                            ( Just dm, Cmd.map DetailMsg dc )
            in
            ( { model
                | listModel = mm
                , detailModel = detail
              }
            , cmd
            )

        DetailMsg lm ->
            case model.detailModel of
                Just dm ->
                    let
                        ( mm, mc ) =
                            Comp.NotificationHookForm.update flags lm dm
                    in
                    ( { model | detailModel = Just mm }
                    , Cmd.map DetailMsg mc
                    )

                Nothing ->
                    ( model, Cmd.none )

        SubmitResp submitType (Ok res) ->
            ( { model
                | formState =
                    if res.success then
                        FormSubmitSuccessful submitType

                    else
                        FormErrorSubmit res.message
                , detailModel =
                    if submitType == SubmitDelete then
                        Nothing

                    else
                        model.detailModel
                , loading = False
              }
            , if submitType == SubmitDelete then
                initCmd flags

              else
                Cmd.none
            )

        SubmitResp _ (Err err) ->
            ( { model | formState = FormErrorHttp err, loading = False }
            , Cmd.none
            )

        NewHookInit ->
            let
                ( mm, mc ) =
                    Comp.NotificationHookForm.init flags
            in
            ( { model | detailModel = Just mm }, Cmd.map DetailMsg mc )

        BackToTable ->
            ( { model | detailModel = Nothing }, initCmd flags )

        Submit ->
            case model.detailModel of
                Just dm ->
                    case Comp.NotificationHookForm.getHook dm of
                        Just data ->
                            case data.eventFilter of
                                Nothing ->
                                    postHook flags data model

                                Just jf ->
                                    ( { model | loading = True }, Api.verifyJsonFilter flags jf (VerifyFilterResp data) )

                        Nothing ->
                            ( { model | formState = FormErrorInvalid }, Cmd.none )

                Nothing ->
                    ( model, Cmd.none )

        RequestDelete ->
            ( { model | deleteConfirm = DeleteConfirmOn }, Cmd.none )

        CancelDelete ->
            ( { model | deleteConfirm = DeleteConfirmOff }, Cmd.none )

        DeleteHookNow id ->
            ( { model | deleteConfirm = DeleteConfirmOff, loading = True }
            , Api.deleteHook flags id (SubmitResp SubmitDelete)
            )


postHook : Flags -> NotificationHook -> Model -> ( Model, Cmd Msg )
postHook flags hook model =
    if hook.id == "" then
        ( { model | loading = True }, Api.createHook flags hook (SubmitResp SubmitCreate) )

    else
        ( { model | loading = True }, Api.updateHook flags hook (SubmitResp SubmitUpdate) )



--- View2


view : Texts -> UiSettings -> Model -> Html Msg
view texts settings model =
    div [ class "flex flex-col" ]
        (case model.detailModel of
            Just msett ->
                viewForm texts settings model msett

            Nothing ->
                viewList texts model
        )


viewState : Texts -> Model -> Html Msg
viewState texts model =
    div
        [ classList
            [ ( S.errorMessage, not (isSuccess model.formState) )
            , ( S.successMessage, isSuccess model.formState )
            , ( "hidden", model.formState == FormStateInitial )
            ]
        , class "mb-2"
        ]
        [ case model.formState of
            FormStateInitial ->
                text ""

            FormSubmitSuccessful SubmitCreate ->
                text texts.hookCreated

            FormSubmitSuccessful SubmitUpdate ->
                text texts.hookUpdated

            FormSubmitSuccessful SubmitDelete ->
                text texts.hookDeleted

            FormErrorSubmit m ->
                text m

            FormErrorHttp err ->
                text (texts.httpError err)

            FormErrorInvalid ->
                case model.jsonFilterError of
                    Just m ->
                        text (texts.invalidJsonFilter m)

                    Nothing ->
                        text texts.formInvalid
        ]


isSuccess : FormState -> Bool
isSuccess state =
    case state of
        FormSubmitSuccessful _ ->
            True

        _ ->
            False


viewForm : Texts -> UiSettings -> Model -> Comp.NotificationHookForm.Model -> List (Html Msg)
viewForm texts settings outerModel model =
    let
        newHook =
            model.hook.id == ""
    in
    [ h1 [ class S.header2 ]
        [ if newHook then
            text texts.addWebhook

          else
            text texts.updateWebhook
        ]
    , MB.view
        { start =
            [ MB.CustomElement <|
                B.primaryButton
                    { handler = onClick Submit
                    , title = texts.basics.submitThisForm
                    , icon = "fa fa-save"
                    , label = texts.basics.submit
                    , disabled = False
                    , attrs = [ href "#" ]
                    }
            , MB.SecondaryButton
                { tagger = BackToTable
                , title = texts.basics.backToList
                , icon = Just "fa fa-arrow-left"
                , label = texts.basics.backToList
                }
            ]
        , end =
            if not newHook then
                [ MB.DeleteButton
                    { tagger = RequestDelete
                    , title = texts.deleteThisHook
                    , icon = Just "fa fa-trash"
                    , label = texts.basics.delete
                    }
                ]

            else
                []
        , rootClasses = "mb-4"
        , sticky = True
        }
    , div [ class "mt-2" ]
        [ viewState texts outerModel
        ]
    , Html.map DetailMsg
        (Comp.NotificationHookForm.view texts.notificationForm settings model)
    , B.loadingDimmer
        { active = outerModel.loading
        , label = texts.basics.loading
        }
    , B.contentDimmer
        (outerModel.deleteConfirm == DeleteConfirmOn)
        (div [ class "flex flex-col" ]
            [ div [ class "text-lg" ]
                [ i [ class "fa fa-info-circle mr-2" ] []
                , text texts.reallyDeleteHook
                ]
            , div [ class "mt-4 flex flex-row items-center" ]
                [ B.deleteButton
                    { label = texts.basics.yes
                    , icon = "fa fa-check"
                    , disabled = False
                    , handler = onClick (DeleteHookNow model.hook.id)
                    , attrs = [ href "#" ]
                    }
                , B.secondaryButton
                    { label = texts.basics.no
                    , icon = "fa fa-times"
                    , disabled = False
                    , handler = onClick CancelDelete
                    , attrs = [ href "#", class "ml-2" ]
                    }
                ]
            ]
        )
    ]


viewList : Texts -> Model -> List (Html Msg)
viewList texts model =
    [ MB.view
        { start = []
        , end =
            [ MB.PrimaryButton
                { tagger = NewHookInit
                , title = texts.newHook
                , icon = Just "fa fa-plus"
                , label = texts.newHook
                }
            ]
        , rootClasses = "mb-4"
        , sticky = True
        }
    , Html.map TableMsg
        (Comp.NotificationHookTable.view texts.notificationTable
            model.listModel
            model.items
        )
    ]
