module Panes.Modal.AddDatabase exposing
    ( component
    , Model
    , Msg
    )

import Html exposing (Html, div, text)
import Html.Attributes as HA exposing (class)
import Html.Events as HE
import Triple exposing (triple)
import Panes exposing (..)
import Data exposing (Id)
import Data.Schema exposing (Schema)
import Network.Messages
import PaneMeta exposing (PaneMeta)
import Dict
import Regex
import Url
import Data.Info
import Tools

component : RawComponent () Model Msg
component =
    { init = init
    , view = view
    , title = title
    , update = update
    , apply = apply
    , save = save
    , subscription = subscription
    }

type alias Model =
    { name: String
    , schema: Maybe String
    , key: Maybe String
    , keySecureSaved: Bool
    , modalId: Maybe Int
    , access: List Data.Info.DbAccess
    }

type Msg
    = None
    | SendEvent Event
    | SetName String
    | SetSchema String
    | SetKeySecureSaved Bool

invalidNameChars : Regex.Regex
invalidNameChars = Regex.fromString "[^\\w-]"
    |> Maybe.withDefault Regex.never

init : Init () Model Msg
init meta () =
    triple
        { name = ""
        , schema = Maybe.map .schemas meta.info
            |> Maybe.withDefault []
            |> List.head
        , key = Nothing
        , keySecureSaved = False
        , modalId = Nothing
        , access = []
        }
        Cmd.none
        []
    
view : View Model Msg
view { meta, state } =
    case state.key of
        Nothing ->
            viewCreationPhase1 { meta = meta, state = state }
        Just key ->
            viewCreationPhase2 meta key state

viewCreationPhase1 : View Model Msg
viewCreationPhase1 { meta, state } =
    div [ class "modal-add-database modal-add-database-phase1" ]
        [ Html.p []
            [ text <| "This dialogue will guide you through the setup process of a new database "
                ++ "for Dacryptero."
            ]
        , Html.h2 []
            [ text "Settings" ]
        , Html.p []
            [ text <| "The main settings for the new database. It is impossible to change them "
                ++ "afterwards."
            ]
        , div [ class "modal-add-database-settings" ]
            [ div []
                [ div [ class "modal-add-database-setting-key" ]
                    [ text "Database Name" ]
                , div [ class "modal-add-database-setting-value" ]
                    [ Html.input
                        [ HA.type_ "text"
                        , HA.value state.name
                        , HE.onInput SetName
                        ] []
                    ]
                ]
            , div []
                [ div [ class "modal-add-database-setting-key" ]
                    [ text "Schema" ]
                , div [ class "modal-add-database-setting-value" ]
                    [ Html.select
                        [ HE.onInput SetSchema ]
                        <| List.map
                            (\name ->
                                Html.option
                                    [ HA.value name
                                    , HA.selected <| Just name == state.schema
                                    ]
                                    [ text name ]
                            )
                        <| Maybe.withDefault []
                        <| Maybe.map .schemas meta.info
                    ]
                ]
            ]
        , Html.button
            [ HA.disabled 
                <| state.name == ""
                || state.schema == Nothing
            , HE.onClick
                <| SendEvent
                <| Panes.Send
                <| Network.Messages.DatabaseAddRequest state.name 
                <| Maybe.withDefault "" state.schema
            ]
            [ text "Create Database" ]
        ]

viewCreationPhase2 : PaneMeta -> String -> Model -> Html Msg
viewCreationPhase2 meta key state =
    div [ class "modal-add-database modal-add-database-phase2" ]
        [ Html.h2 []
            [ text "Master Key" ]
        , Html.p []
            [ text <| "The master key of the new database. This is used to recover lost access. "
                ++ "Please download this document and keep at a secure place. With this key you "
                ++ "can bypass all security measures for this database!"
            ]
        , Html.a
            [ HA.target "_blank" 
            , HA.href
                <| "http://localhost:8015/security/master-key?session="
                ++ Url.percentEncode 
                    (Maybe.withDefault ""
                        <| Maybe.map .uploadToken
                        <| meta.info
                    )
                ++ "&key="
                ++ Url.percentEncode key
            ]
            [ text "Show Master Key" ]
        , Html.label []
            [ Html.input
                [ HA.type_ "checkbox"
                , HA.checked state.keySecureSaved
                , HE.onCheck SetKeySecureSaved
                ] []
            , Html.span []
                [ text "I have saved the Master Key securely." ]
            ]
        , Html.h2 []
            [ text "User Access" ]
        , Html.p []
            [ text <| "Add the user that are allowed to access this database. This will guide you "
                ++ "through the whole credential creation process. You are required to add at "
                ++ "least one user!"
            ]
        , div [ class "modal-add-database-access-list" ]
            <| List.map
                (\access ->
                    div [ class "modal-add-database-access" ]
                        [ Html.img
                            [ HA.src "/img/svgrepo/essential-set-2/id-card-36356.svg" 
                            ] []
                        , if access.fidoDescriptor
                                then Html.img
                                    [ HA.src "/img/svgrepo/essential-set-2/fingerprint-84006.svg"
                                    , HA.title "2 Factor Authentication enabled"
                                    ] []
                                else text ""
                        , div [ class "modal-add-database-access-name" ]
                            [ text access.user ]
                        , Tools.viewDateElement meta.zone meta.now access.created
                        ]
                )
            <| state.access
        , Html.button
            [ HE.onClick <| SendEvent <| Panes.EnterRegisterAccount state.name (Just key) ]
            [ text "Add new User" ]
        , Html.h2 []
            [ text "Create Database" ]
        , Html.button
            [ HE.onClick
                <| Maybe.withDefault None
                <| Maybe.map
                    (SendEvent 
                        << Panes.Send
                        << Network.Messages.DatabaseAddFinish
                    )
                <| state.key
            , HA.disabled <| not state.keySecureSaved || List.isEmpty state.access
            ]
            [ text "Create" ]
        ]

title : Title Model
title { state } =
    if state.key == Nothing
    then "Add Database"
    else "Add Database: " ++ state.name

update : Update Model Msg
update msg { state } =
    case msg of
        None -> triple
            state
            Cmd.none
            []
        SendEvent event -> triple
            state
            Cmd.none
            [ event ]
        SetName name -> triple
            { state 
            | name = 
                String.left 50 name
                |> String.replace " " "-"
                |> String.toLower
                |> Regex.replace invalidNameChars 
                    (\match -> case match.match of
                        "ä" -> "ae"
                        "á" -> "a"
                        "à" -> "a"
                        "â" -> "a"
                        "é" -> "e"
                        "è" -> "e"
                        "ê" -> "e"
                        "í" -> "i"
                        "ì" -> "i"
                        "î" -> "i"
                        "ö" -> "oe"
                        "ó" -> "o"
                        "ò" -> "o"
                        "ô" -> "o"
                        "ü" -> "ue"
                        "ú" -> "u"
                        "ù" -> "u"
                        "û" -> "u"
                        "ß" -> "ss"
                        _ -> "_"
                    )
            }
            Cmd.none
            []
        SetSchema name -> triple
            { state | schema = Just name }
            Cmd.none
            []
        SetKeySecureSaved mode -> triple
            { state | keySecureSaved = mode }
            Cmd.none
            []
        
apply : Apply Model Msg
apply event { state } =
    case event of
        Network.Messages.InfoSend info -> triple 
            { state
            | schema = case state.schema of
                Just x -> Just x
                Nothing -> List.head info.schemas
            }
            Cmd.none
            []
        Network.Messages.DatabaseAddRequestInfo info ->
            if state.key == Just info.key
                || (state.key == Nothing
                    && state.name == info.database
                    && state.schema == Just info.schema
                    )
            then triple
                { state
                | key = Just info.key 
                , access = info.access
                }
                Cmd.none
                []
            else triple state Cmd.none []
        Network.Messages.DatabaseCreated id ->
            if state.key == Just id
            then triple state Cmd.none
                <| Maybe.withDefault []
                <| Maybe.map
                    (List.singleton << Panes.CloseModal)
                <| state.modalId
            else triple state Cmd.none []
        _ -> triple state Cmd.none []

save : Save Model
save state =
    case state.key of
        Just key -> [ Panes.Send <| Network.Messages.DatabaseCancelCreation key ]
        Nothing -> []

subscription : Subscription Model Msg
subscription _ = Sub.none
