{-
   Copyright 2020 Eike K. & Contributors

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


module Comp.UiSettingsManage exposing
    ( Model
    , Msg(..)
    , UpdateResult
    , init
    , update
    , view2
    )

import Api
import Api.Model.BasicResult exposing (BasicResult)
import Comp.Basic
import Comp.MenuBar as MB
import Comp.UiSettingsForm
import Data.AccountScope exposing (AccountScope)
import Data.AppEvent exposing (AppEvent(..))
import Data.Flags exposing (Flags)
import Data.UiSettings exposing (StoredUiSettings, UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Http
import Messages.Comp.UiSettingsManage exposing (Texts)
import Page.Search.Data exposing (Msg(..))
import Process
import Styles as S
import Task


type alias Model =
    { formModel : FormView
    , formResult : FormResult
    , formData : Maybe FormData
    }


type alias FormData =
    { userSettings : StoredUiSettings
    , userModel : Comp.UiSettingsForm.Model
    , collSettings : StoredUiSettings
    , collModel : Comp.UiSettingsForm.Model
    }


type FormView
    = ViewLoading
    | ViewUser
    | ViewCollective


type FormResult
    = FormInit
    | FormUnchanged
    | FormSaved
    | FormHttpError Http.Error
    | FormUnknownError


type Msg
    = UiFormMsg AccountScope Comp.UiSettingsForm.Msg
    | Submit
    | SaveSettingsResp (Result Http.Error BasicResult)
    | ReceiveServerSettings (Result Http.Error ( StoredUiSettings, StoredUiSettings ))
    | ToggleExpandCollapse
    | SwitchForm AccountScope
    | ResetFormState


init : Flags -> ( Model, Cmd Msg )
init flags =
    ( { formModel = ViewLoading
      , formData = Nothing
      , formResult = FormInit
      }
    , Cmd.batch
        [ Api.getClientSettingsRaw flags ReceiveServerSettings
        ]
    )


getViewScope : Model -> AccountScope
getViewScope model =
    case model.formModel of
        ViewCollective ->
            Data.AccountScope.Collective

        ViewUser ->
            Data.AccountScope.User

        _ ->
            Data.AccountScope.User



--- update


type alias UpdateResult =
    { model : Model
    , cmd : Cmd Msg
    , sub : Sub Msg
    , appEvent : AppEvent
    }


unit : Model -> UpdateResult
unit model =
    UpdateResult model Cmd.none Sub.none AppNothing


update : Flags -> UiSettings -> Msg -> Model -> UpdateResult
update flags settings msg model =
    case msg of
        UiFormMsg scope lm ->
            case model.formData of
                Nothing ->
                    unit model

                Just data ->
                    case scope of
                        Data.AccountScope.Collective ->
                            let
                                ( m_, sett ) =
                                    Comp.UiSettingsForm.update flags data.collSettings lm data.collModel
                            in
                            unit
                                { model
                                    | formData =
                                        Just
                                            { data
                                                | collSettings = Maybe.withDefault data.collSettings sett
                                                , collModel = m_
                                            }
                                }

                        Data.AccountScope.User ->
                            let
                                ( m_, sett ) =
                                    Comp.UiSettingsForm.update flags data.userSettings lm data.userModel
                            in
                            unit
                                { model
                                    | formData =
                                        Just
                                            { data
                                                | userSettings = Maybe.withDefault data.userSettings sett
                                                , userModel = m_
                                            }
                                }

        Submit ->
            case ( model.formModel, model.formData ) of
                ( ViewCollective, Just data ) ->
                    { model = { model | formResult = FormInit }
                    , cmd =
                        Api.saveClientSettings flags
                            data.collSettings
                            Data.AccountScope.Collective
                            SaveSettingsResp
                    , sub = Sub.none
                    , appEvent = AppNothing
                    }

                ( ViewUser, Just data ) ->
                    { model = { model | formResult = FormInit }
                    , cmd =
                        Api.saveClientSettings flags
                            data.userSettings
                            Data.AccountScope.User
                            SaveSettingsResp
                    , sub = Sub.none
                    , appEvent = AppNothing
                    }

                _ ->
                    unit model

        SaveSettingsResp (Ok res) ->
            case ( res.success, model.formData ) of
                ( True, Just data ) ->
                    let
                        result =
                            update flags
                                settings
                                (ReceiveServerSettings (Ok ( data.collSettings, data.userSettings )))
                                { model | formResult = FormSaved }

                        cmd =
                            Process.sleep 2000
                                |> Task.perform (\_ -> ResetFormState)
                    in
                    { result | appEvent = AppReloadUiSettings, cmd = Cmd.batch [ cmd, result.cmd ] }

                _ ->
                    unit { model | formResult = FormUnknownError }

        SaveSettingsResp (Err err) ->
            UpdateResult { model | formResult = FormHttpError err } Cmd.none Sub.none AppNothing

        ReceiveServerSettings (Ok ( coll, user )) ->
            let
                collDefaults =
                    Data.UiSettings.defaults

                userDefaults =
                    Data.UiSettings.merge coll collDefaults

                ( ( um, uc ), ( cm, cc ) ) =
                    case model.formData of
                        Just data ->
                            ( Comp.UiSettingsForm.initData flags user userDefaults data.userModel
                            , Comp.UiSettingsForm.initData flags coll collDefaults data.collModel
                            )

                        Nothing ->
                            ( Comp.UiSettingsForm.init flags user userDefaults
                            , Comp.UiSettingsForm.init flags coll collDefaults
                            )

                model_ =
                    { model
                        | formData =
                            Just
                                { userSettings = user
                                , userModel = um
                                , collSettings = coll
                                , collModel = cm
                                }
                        , formModel =
                            case model.formModel of
                                ViewLoading ->
                                    ViewUser

                                _ ->
                                    model.formModel
                    }

                cmds =
                    Cmd.batch
                        [ Cmd.map (UiFormMsg Data.AccountScope.User) uc
                        , Cmd.map (UiFormMsg Data.AccountScope.Collective) cc
                        ]
            in
            UpdateResult model_ cmds Sub.none AppNothing

        ReceiveServerSettings (Err err) ->
            unit { model | formResult = FormHttpError err }

        ToggleExpandCollapse ->
            let
                lm =
                    UiFormMsg (getViewScope model) Comp.UiSettingsForm.toggleAllTabs
            in
            update flags settings lm model

        SwitchForm scope ->
            let
                forUser =
                    unit { model | formModel = ViewUser }

                forColl =
                    unit { model | formModel = ViewCollective }
            in
            Data.AccountScope.fold forUser forColl scope

        ResetFormState ->
            case model.formResult of
                FormSaved ->
                    unit { model | formResult = FormInit }

                _ ->
                    unit model


isError : Model -> Bool
isError model =
    case model.formResult of
        FormSaved ->
            False

        FormInit ->
            False

        FormUnchanged ->
            True

        FormHttpError _ ->
            True

        FormUnknownError ->
            True


isSuccess : Model -> Bool
isSuccess model =
    not (isError model)


view2 : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
view2 texts flags _ classes model =
    let
        scope =
            getViewScope model
    in
    div [ class classes ]
        [ MB.view
            { start =
                [ MB.PrimaryButton
                    { tagger = Submit
                    , label = texts.basics.submit
                    , title = texts.saveSettings
                    , icon = Just "fa fa-save"
                    }
                , MB.SecondaryButton
                    { tagger = ToggleExpandCollapse
                    , label = ""
                    , title = texts.expandCollapse
                    , icon = Just "fa fa-compress"
                    }
                ]
            , end =
                [ MB.RadioButton
                    { tagger = \_ -> SwitchForm Data.AccountScope.User
                    , label = texts.accountScope Data.AccountScope.User
                    , value = Data.AccountScope.fold True False scope
                    , id = "ui-settings-chooser-user"
                    }
                , MB.RadioButton
                    { tagger = \_ -> SwitchForm Data.AccountScope.Collective
                    , label = texts.accountScope Data.AccountScope.Collective
                    , value = Data.AccountScope.fold False True scope
                    , id = "ui-settings-chooser-collective"
                    }
                ]
            , rootClasses = "mb-4"
            , sticky = True
            }
        , div
            [ classList
                [ ( S.successMessage, isSuccess model )
                , ( S.errorMessage, isError model )
                , ( "hidden", model.formResult == FormInit )
                ]
            ]
            [ case model.formResult of
                FormInit ->
                    text ""

                FormUnchanged ->
                    text texts.settingsUnchanged

                FormHttpError err ->
                    text (texts.httpError err)

                FormSaved ->
                    text texts.settingsSaved

                FormUnknownError ->
                    text texts.unknownSaveError
            ]
        , case model.formModel of
            ViewLoading ->
                div [ class "h-24 md:relative" ]
                    [ Comp.Basic.loadingDimmer
                        { label = ""
                        , active = True
                        }
                    ]

            ViewCollective ->
                case model.formData of
                    Just data ->
                        div []
                            [ h2 [ class S.header2 ]
                                [ text texts.collectiveHeader
                                ]
                            , div [ class "py-1 opacity-80" ]
                                [ text texts.collectiveInfo
                                ]
                            , Html.map (UiFormMsg scope)
                                (Comp.UiSettingsForm.view2
                                    texts.uiSettingsForm
                                    flags
                                    data.collSettings
                                    data.collModel
                                )
                            ]

                    Nothing ->
                        span [ class "hidden" ] []

            ViewUser ->
                case model.formData of
                    Just data ->
                        div []
                            [ h2 [ class S.header2 ]
                                [ text texts.userHeader
                                ]
                            , div [ class "py-1 opacity-80" ]
                                [ text texts.userInfo
                                ]
                            , Html.map (UiFormMsg scope)
                                (Comp.UiSettingsForm.view2 texts.uiSettingsForm
                                    flags
                                    data.userSettings
                                    data.userModel
                                )
                            ]

                    Nothing ->
                        span [ class "hidden" ] []
        ]
