module Panes.Modal.Upload 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 Lazy exposing (Lazy)
import Network.Messages
import PaneMeta exposing (PaneMeta)
import File exposing (File)
import File.Select
import Time
import Http
import Url
import Json.Decode as JD exposing (Decoder)
import Notification
import Notification exposing (Notification)
import Tools

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

type alias Model =
    { person: Id
    , parent: Maybe Id
    , hover: Bool
    }

type Msg
    = None
    | SendEvent Event
    | RequestFiles
    | SetHover Bool
    | GotFiles File (List File)
    | Uploaded String (Result Http.Error ())

init : Init (Id, Maybe Id) Model Msg
init _ (person, parent) =
    triple
        { person = person
        , parent = parent
        , hover = False
        }
        Cmd.none
        []

handler : String -> Decoder msg -> Html.Attribute msg
handler event decoder =
    HE.custom event
        <| JD.map
            (\msg ->
                { message = msg
                , stopPropagation = True
                , preventDefault = True
                }
            )
        <| decoder

view : View Model Msg
view { meta, state } =
    div [ class "modal-upload"
        , HA.classList
            [ ("modal-upload", True)
            , ("modal-upload-hover", state.hover)
            ]
        , handler "dragenter" <| JD.succeed <| SetHover True
        , handler "dragover" <| JD.succeed <| SetHover True
        , handler "dragleave" <| JD.succeed <| SetHover False
        , handler "drop"
            <| JD.at [ "dataTransfer", "files" ]
            <| JD.oneOrMore GotFiles
            <| File.decoder
        ]
        [ Html.button
            [ HE.onClick <| RequestFiles ]
            [ text "Upload" ]
        , if state.hover
            then div [ class "modal-upload-hint" ]
                [ text "Drop file(s) to upload" ]
            else div [ class "modal-upload-hint" ]
                [ text "Drag and drop files here to upload" ]
        ]

title : Title Model
title { state } =
    "Upload file to #" ++ state.person

fileTag : Model -> File -> String
fileTag model file =
    String.join "-"
        [ model.person
        , Maybe.withDefault "" model.parent
        , File.name file
        , File.mime file
        , String.fromInt <| File.size file
        , String.fromInt <| Time.posixToMillis <| File.lastModified file
        ]

update : Update Model Msg
update msg { meta, state } =
    case Debug.log "Panes.Modal.Upload:update:msg" msg of
        None -> triple
            state
            Cmd.none
            []
        SendEvent event -> triple
            state
            Cmd.none
            [ event ]
        RequestFiles -> triple
            state
            (File.Select.files [] GotFiles)
            []
        SetHover hover -> triple { state | hover = hover } Cmd.none []
        GotFiles file1 files -> triple
            { state | hover = False }
            (Cmd.batch
                <| List.map
                    (\file ->
                        Http.request
                            { method = "PUT"
                            , headers = []
                            , url = (++) "http://localhost:8015/upload?"
                                <| String.join "&"
                                <| List.map 
                                    (\(k, v) -> Url.percentEncode k ++ "=" ++ Url.percentEncode v)
                                <| List.filterMap identity
                                    [ Just ("person", state.person)
                                    , Maybe.map (Tuple.pair "parent") state.parent
                                    , Just ("name", File.name file)
                                    , Just ("mime", File.mime file)
                                    , Maybe.map (Tuple.pair "token")
                                        <| Maybe.map .uploadToken meta.info
                                    ]
                            , body = Http.fileBody file
                            , expect = Http.expectWhatever (Uploaded <| fileTag state file)
                            , timeout = Nothing
                            , tracker = Just <| fileTag state file
                            }
                    )
                <| file1 :: files
            )
            <| 
                ( List.map
                    (\file -> Panes.AddUpload
                        { tag = fileTag state file
                        , name = File.name file
                        , mime = File.mime file
                        , person = state.person
                        , parent = state.parent
                        , progress = Nothing
                        }
                    )
                    <| file1 :: files
                )
                ++
                ( List.map
                    (\file -> Panes.SetNotification
                        { id = Just <| "upload-" ++ fileTag state file
                        , img = Just "/img/svgrepo/essential-set-2/cloud-computing-36328.svg"
                        , title = "Upload"
                        , description = File.name file
                        , progress = Notification.UndefinedProgress
                        , close = Nothing
                        }
                    )
                    <| file1 :: files
                )
        Uploaded tag (Ok ()) ->
            triple state Cmd.none
                [ Panes.RemoveUpload tag
                , Panes.EditNotifcation
                    { id = "upload-" ++ tag
                    , img = Nothing
                    , title = Nothing
                    , description = Nothing
                    , progress = Just <| Notification.Progress 1
                    , close = Just <| Just <| Tools.addMs 5000 meta.now
                    }
                ]
        Uploaded tag (Err error) ->
            triple state Cmd.none
                [ Panes.RemoveUpload tag
                , Panes.EditNotifcation
                    { id = "upload-" ++ tag
                    , img = Nothing
                    , title = Nothing
                    , description = Nothing
                    , progress = Just <| Notification.Progress 1
                    , close = Just <| Just <| Tools.addMs 5000 meta.now
                    }
                , Panes.AddHttpError error
                ]

apply : Apply Model Msg
apply event { state } =
    case event of
        _ -> triple state Cmd.none []

save : Save Model
save _ = []

subscription : Subscription Model Msg
subscription _ = Sub.none

