module Comp.ItemCardList exposing
    ( Model
    , Msg(..)
    , init
    , nextItem
    , prevItem
    , update
    , updateDrag
    , view
    )

import Api.Model.HighlightEntry exposing (HighlightEntry)
import Api.Model.ItemLight exposing (ItemLight)
import Api.Model.ItemLightGroup exposing (ItemLightGroup)
import Api.Model.ItemLightList exposing (ItemLightList)
import Data.Direction
import Data.Fields
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.Items
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Markdown
import Page exposing (Page(..))
import Util.ItemDragDrop as DD
import Util.List
import Util.String
import Util.Time


type alias Model =
    { results : ItemLightList
    }


type Msg
    = SetResults ItemLightList
    | AddResults ItemLightList
    | ItemDDMsg DD.Msg


init : Model
init =
    { results = Api.Model.ItemLightList.empty
    }


nextItem : Model -> String -> Maybe ItemLight
nextItem model id =
    List.concatMap .items model.results.groups
        |> Util.List.findNext (\i -> i.id == id)


prevItem : Model -> String -> Maybe ItemLight
prevItem model id =
    List.concatMap .items model.results.groups
        |> Util.List.findPrev (\i -> i.id == id)



--- Update


update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
update flags msg model =
    let
        res =
            updateDrag DD.init flags msg model
    in
    ( res.model, res.cmd )


type alias UpdateResult =
    { model : Model
    , cmd : Cmd Msg
    , dragModel : DD.Model
    }


updateDrag :
    DD.Model
    -> Flags
    -> Msg
    -> Model
    -> UpdateResult
updateDrag dm _ msg model =
    case msg of
        SetResults list ->
            let
                newModel =
                    { model | results = list }
            in
            UpdateResult newModel Cmd.none dm

        AddResults list ->
            if list.groups == [] then
                UpdateResult model Cmd.none dm

            else
                let
                    newModel =
                        { model | results = Data.Items.concat model.results list }
                in
                UpdateResult newModel Cmd.none dm

        ItemDDMsg lm ->
            let
                ddd =
                    DD.update lm dm
            in
            UpdateResult model Cmd.none ddd.model



--- View


view : Maybe String -> UiSettings -> Model -> Html Msg
view current settings model =
    div [ class "ui container" ]
        (List.map (viewGroup current settings) model.results.groups)


viewGroup : Maybe String -> UiSettings -> ItemLightGroup -> Html Msg
viewGroup current settings group =
    div [ class "item-group" ]
        [ div [ class "ui horizontal divider header item-list" ]
            [ i [ class "calendar alternate outline icon" ] []
            , text group.name
            ]
        , div [ class "ui stackable three cards" ]
            (List.map (viewItem current settings) group.items)
        ]


viewItem : Maybe String -> UiSettings -> ItemLight -> Html Msg
viewItem current settings item =
    let
        dirIcon =
            i [ class (Data.Direction.iconFromMaybe item.direction) ] []

        corr =
            List.filterMap identity [ item.corrOrg, item.corrPerson ]
                |> List.map .name
                |> List.intersperse ", "
                |> String.concat

        conc =
            List.filterMap identity [ item.concPerson, item.concEquip ]
                |> List.map .name
                |> List.intersperse ", "
                |> String.concat

        folder =
            Maybe.map .name item.folder
                |> Maybe.withDefault ""

        dueDate =
            Maybe.map Util.Time.formatDateShort item.dueDate
                |> Maybe.withDefault ""

        isConfirmed =
            item.state /= "created"

        newColor =
            "blue"

        fieldHidden f =
            Data.UiSettings.fieldHidden settings f
    in
    a
        ([ classList
            [ ( "ui fluid card", True )
            , ( newColor, not isConfirmed )
            , ( "current", current == Just item.id )
            ]
         , id item.id
         , Page.href (ItemDetailPage item.id)
         ]
            ++ DD.draggable ItemDDMsg item.id
        )
        [ div [ class "content" ]
            [ if fieldHidden Data.Fields.Direction then
                div [ class "header" ]
                    [ Util.String.underscoreToSpace item.name |> text
                    ]

              else
                div
                    [ class "header"
                    , Data.Direction.labelFromMaybe item.direction
                        |> title
                    ]
                    [ dirIcon
                    , Util.String.underscoreToSpace item.name
                        |> text
                    ]
            , div
                [ classList
                    [ ( "ui right corner label", True )
                    , ( newColor, True )
                    , ( "invisible", isConfirmed )
                    ]
                , title "New"
                ]
                [ i [ class "exclamation icon" ] []
                ]
            , div
                [ classList
                    [ ( "meta", True )
                    , ( "invisible hidden", fieldHidden Data.Fields.Date )
                    ]
                ]
                [ Util.Time.formatDate item.date |> text
                ]
            , div [ class "meta description" ]
                [ div
                    [ classList
                        [ ( "ui right floated tiny labels", True )
                        , ( "invisible hidden", item.tags == [] || fieldHidden Data.Fields.Tag )
                        ]
                    ]
                    (List.map
                        (\tag ->
                            div
                                [ classList
                                    [ ( "ui basic label", True )
                                    , ( Data.UiSettings.tagColorString tag settings, True )
                                    ]
                                ]
                                [ text tag.name ]
                        )
                        item.tags
                    )
                ]
            ]
        , div
            [ classList
                [ ( "content", True )
                , ( "invisible hidden"
                  , settings.itemSearchNoteLength
                        <= 0
                        || Util.String.isNothingOrBlank item.notes
                  )
                ]
            ]
            [ span [ class "small-info" ]
                [ Maybe.withDefault "" item.notes
                    |> Util.String.ellipsis settings.itemSearchNoteLength
                    |> text
                ]
            ]
        , div [ class "content" ]
            [ div [ class "ui horizontal list" ]
                [ div
                    [ classList
                        [ ( "item", True )
                        , ( "invisible hidden"
                          , fieldHidden Data.Fields.CorrOrg
                                && fieldHidden Data.Fields.CorrPerson
                          )
                        ]
                    , title "Correspondent"
                    ]
                    [ Icons.correspondentIcon ""
                    , text " "
                    , Util.String.withDefault "-" corr |> text
                    ]
                , div
                    [ classList
                        [ ( "item", True )
                        , ( "invisible hidden"
                          , fieldHidden Data.Fields.ConcPerson
                                && fieldHidden Data.Fields.ConcEquip
                          )
                        ]
                    , title "Concerning"
                    ]
                    [ Icons.concernedIcon
                    , text " "
                    , Util.String.withDefault "-" conc |> text
                    ]
                , div
                    [ classList
                        [ ( "item", True )
                        , ( "invisible hidden", fieldHidden Data.Fields.Folder )
                        ]
                    , title "Folder"
                    ]
                    [ Icons.folderIcon ""
                    , text " "
                    , Util.String.withDefault "-" folder |> text
                    ]
                ]
            , div [ class "right floated meta" ]
                [ div [ class "ui horizontal list" ]
                    [ div
                        [ class "item"
                        , title "Source"
                        ]
                        [ text item.source
                        ]
                    , div
                        [ classList
                            [ ( "item", True )
                            , ( "invisible hidden"
                              , item.dueDate
                                    == Nothing
                                    || fieldHidden Data.Fields.DueDate
                              )
                            ]
                        , title ("Due on " ++ dueDate)
                        ]
                        [ div
                            [ class "ui basic grey label"
                            ]
                            [ Icons.dueDateIcon ""
                            , text (" " ++ dueDate)
                            ]
                        ]
                    ]
                ]
            ]
        , div
            [ classList
                [ ( "content search-highlight", True )
                , ( "invisible hidden", item.highlighting == [] )
                ]
            ]
            [ div [ class "ui list" ]
                (List.map renderHighlightEntry item.highlighting)
            ]
        ]


renderHighlightEntry : HighlightEntry -> Html Msg
renderHighlightEntry entry =
    let
        stripWhitespace str =
            String.trim str
                |> String.replace "```" ""
                |> String.replace "\t" "  "
                |> String.replace "\n\n" "\n"
                |> String.lines
                |> List.map String.trim
                |> String.join "\n"
    in
    div [ class "item" ]
        [ div [ class "content" ]
            (div [ class "header" ]
                [ i [ class "caret right icon" ] []
                , text (entry.name ++ ":")
                ]
                :: List.map
                    (\str ->
                        Markdown.toHtml [ class "description" ] <|
                            (stripWhitespace str ++ "…")
                    )
                    entry.lines
            )
        ]
