module Panes.Home 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 Lazy exposing (Lazy)
import Data.Info exposing (Info)
import Network.Messages
import Dict
import ContextMenu exposing (ContextMenu, Item)
import Data.Search exposing (SearchValue(..))
import Tools
import PaneMeta

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

type alias Model = Lazy () LoadedModel

type alias LoadedModel =
    { info: Info
    , menuDb: ContextMenu Data.Info.DbInfo
    , menuSchema: ContextMenu String
    }

type Msg
    = None
    | SendEvent Event
    | WrapMenuDb (ContextMenu.Msg Data.Info.DbInfo)
    | WrapMenuSchema (ContextMenu.Msg String)

init : Init () Model Msg
init _ () =
    triple
        (Lazy.Loading ())
        Cmd.none
        [ Send <| Network.Messages.InfoRequest
        ]

contextMenuConfig : ContextMenu.Config
contextMenuConfig = ContextMenu.defaultConfig |> \conf ->
    { conf 
    | fontFamily = "inherit"
    , rounded = True
    }

bool2Maybe : Bool -> a -> Maybe a
bool2Maybe check value =
    if check then Just value else Nothing

viewMenuDb : Data.Info.DbInfo -> List (List (Item, Msg))
viewMenuDb info =
    List.filterMap identity
    [ bool2Maybe (not info.connected)
        [ Tuple.pair
            (ContextMenu.item "Connect")
            <| SendEvent
            <| Panes.Send
            <| Network.Messages.DatabaseConnect
            <| Just info.name
        , Tuple.pair
            (ContextMenu.item "Restore Access")
            <| SendEvent
            <| Panes.OpenDatabaseAccess info.name
        ]
    , bool2Maybe (info.connected && info.hasConfidential)
        [ Tuple.pair
            (ContextMenu.item "Add Interview")
            <| SendEvent
            <| Panes.Send
            <| Network.Messages.DataInterviewAddRequest info.name
        ]
    , bool2Maybe info.connected
        [ Tuple.pair
            (ContextMenu.item "Share")
            None
        , Tuple.pair
            (ContextMenu.itemWithAnnotation "Manage Access"
                "add accounts, change password, remove access, ..."
            )
            <| SendEvent
            <| Panes.OpenDatabaseAccess info.name
        ]
    , Just
        [ Tuple.pair 
            (ContextMenu.item "Remove Confidential Database"
                |> ContextMenu.disabled (not info.hasConfidential)
            )
            None
        , Tuple.pair
            (ContextMenu.item "Add Confidential Database"
                |> ContextMenu.disabled info.hasConfidential
            )
            None
        ]
    , bool2Maybe info.connected
        [ Tuple.pair
            (ContextMenu.itemWithAnnotation "Re-Index Database"
                "This will rebuild the complete search index"
            )
            <| SendEvent
            <| Panes.Send
            <| Network.Messages.PerformReindex info.name
        ]
    , Just
        [ (ContextMenu.item "Backup", None)
        , (ContextMenu.item "Remove", None)
        ]
    ]

viewMenuSchema : Info -> String -> List (List (Item, Msg))
viewMenuSchema info name =
    [
        [ Tuple.pair
            (ContextMenu.item "Inspect")
            None
        , Tuple.pair
            (ContextMenu.item "Download")
            None
        ],
        [ Tuple.pair
            (ContextMenu.item "Remove"
                |> ContextMenu.disabled
                    (List.any
                        ((==) name << .roleSchema)
                        info.database
                    )
            )
            None
        ]
    ]

view : View Model Msg
view data =
    case data.state of
        Lazy.Loading _ ->
            div [ class "pane-home" ]
                [ text "Loading..."]
        Lazy.Loaded model ->
            div [ class "pane-home" ]
                [ div [ class "pane-home-user" ]
                    [ div [] [ text "Username: " ]
                    , div [] [ text model.info.user ]
                    ]
                , viewDatabaseInfo data.meta model.info
                , ContextMenu.view
                    contextMenuConfig
                    WrapMenuDb
                    viewMenuDb
                    model.menuDb
                , viewSchemaInfo model.info
                , ContextMenu.view
                    contextMenuConfig
                    WrapMenuSchema
                    (viewMenuSchema model.info)
                    model.menuSchema
                ]

viewDatabaseInfo : PaneMeta.PaneMeta -> Info -> Html Msg
viewDatabaseInfo meta info =
    div [ class "pane-home-db-info" ]
        [ Html.h3 []
            [ text "Databases" ]
        , Html.ul []
            <| List.map
                (\db ->
                    Html.li 
                        [ ContextMenu.open WrapMenuDb db ]
                        [ div [ class "pane-home-db-name" ]
                            [ text db.name ]
                        , case db.unlocked of
                            Nothing -> text ""
                            Just time ->
                                div
                                    [ HA.classList
                                        [ ("pane-home-db-is-unlocked", True)
                                        ]
                                    , HA.title
                                        <| "Datebase was unlocked at "
                                        ++ Tools.viewDateTime meta.zone time
                                        ++ ".\nThe key is right now unprotected in memory."
                                    ] []
                        , div
                            [ HA.classList
                                [ ("pane-home-db-state-confidential", True)
                                , ("pane-home-db-is-confidential", db.hasConfidential)
                                ]
                            , HA.title <|
                                if db.hasConfidential
                                then "Confidential Database is attached. Remove it to work with pseudonym data"
                                else "No Confidential Database attached. No personal information available."
                            ] []
                        , div
                            [ HA.classList
                                [ ("pane-home-db-state-connected", True)
                                , ("pane-home-db-is-connected", db.connected)
                                ]
                            , HA.title <|
                                if db.connected
                                then "Database connected"
                                else "Database is not connected. Maybe missing credentials"
                            ] []
                        , div
                            [ class "pane-home-db-menu"
                            , HA.title "more options"
                            , ContextMenu.openClick True WrapMenuDb db
                            ] []
                        ]
                )
            <| info.database
        , div [ class "pane-home-info-stats" ]
            [ div []
                <| List.singleton
                <| text
                <| String.concat
                [ String.fromInt 
                    <| List.length
                    <| List.filter .connected
                    <| info.database
                , "/"
                , String.fromInt <| List.length info.database
                , " Database(s) connected"
                ]
            , div []
                <| List.singleton
                <| text
                <| String.concat
                [ String.fromInt 
                    <| List.length
                    <| List.filter .hasConfidential
                    <| info.database
                , "/"
                , String.fromInt <| List.length info.database
                , " Database(s) contain private information"
                ]
            ]
        , div [ class "utils-links" ]
            [ Html.a 
                [ class "utils-link"
                , HE.onClick <| SendEvent <| Panes.OpenAddDatabase
                ]
                [ text "Create Database" ]
            , Html.a [ class "utils-link" ]
                [ text "Import Database" ]
            , Html.a
                [ class "utils-link"
                , HE.onClick
                    <| SendEvent
                    <| Panes.Send
                    <| Network.Messages.DatabaseConnect Nothing
                ]
                [ text "Connect Database" ]
            ]
        ]

viewSchemaInfo : Info -> Html Msg
viewSchemaInfo info =
    div [ class "pane-home-schema-info" ]
        [ Html.h3 []
            [ text "Schemas" ]
        , Html.ul []
            <| List.map
                (\schema ->
                    Html.li 
                        [ ContextMenu.open
                            WrapMenuSchema
                            schema
                        ]
                        [ div [ class "pane-home-schema-name" ]
                            [ text schema ]
                        , div [ class "pane-home-schema-usage" ]
                            <| List.map
                                (\{ name } ->
                                    div [ class "utils-database" ]
                                        [ text name ]
                                )
                            <| List.filter (\x -> x.roleSchema == schema)
                            <| info.database
                        , div
                            [ class "pane-home-schema-menu"
                            , HA.title "more options"
                            , ContextMenu.openClick True WrapMenuSchema schema
                            ] []
                        ]
                )
            <| info.schemas
        , div [ class "utils-links" ]
            [ Html.a [ class "utils-link" ]
                [ text "Add Schema" ]
            ]
        ]

update : Update Model Msg
update msg { state } =
    case (msg, state ) of
        (None, _) -> triple
            state
            Cmd.none
            []
        (SendEvent event, _) -> triple
            state
            Cmd.none
            [ event ]
        (_, Lazy.Loading _) -> triple state Cmd.none []
        (WrapMenuDb sub, Lazy.Loaded model) ->
            ContextMenu.update sub model.menuDb
            |> Tuple.mapBoth
                (\x -> Lazy.Loaded { model | menuDb = x })
                (Cmd.map WrapMenuDb)
            |> Triple.insertThird []
        (WrapMenuSchema sub, Lazy.Loaded model) ->
            ContextMenu.update sub model.menuSchema
            |> Tuple.mapBoth
                (\x -> Lazy.Loaded { model | menuSchema = x})
                (Cmd.map WrapMenuSchema)
            |> Triple.insertThird []

apply : Apply Model Msg
apply event data =
    case event of
        Network.Messages.InfoSend info ->
            let
                (menuDb, cmd1) = ContextMenu.init
                (menuSchema, cmd2) = ContextMenu.init

                cmds = Cmd.batch
                    [ Cmd.map WrapMenuDb cmd1
                    , Cmd.map WrapMenuSchema cmd2
                    ]
            in triple
                    (Lazy.Loaded
                        { info = info
                        , menuDb = menuDb
                        , menuSchema = menuSchema
                        }
                    )
                    cmds
                    []
                -- <| List.map (Send << Network.Messages.SchemaRequest)
                -- <| List.filter
                --     (\x -> not <| Dict.member x data.meta.schemas)
                -- <| info.schemas
        _ -> triple data.state Cmd.none []

save : Save Model
save _ = []

subscription : Subscription Model Msg
subscription { state } =
    case state of
        Lazy.Loading _ -> Sub.none
        Lazy.Loaded model ->
            Sub.batch
                [ Sub.map WrapMenuDb
                    <| ContextMenu.subscriptions model.menuDb
                , Sub.map WrapMenuSchema
                    <| ContextMenu.subscriptions model.menuSchema
                ]
