module Config.Helpers.Articles.Markdown exposing (..)

-- import Config.Style.Colour.Helpers exposing (colourTheme)

import Config.Helpers.Cards.Inner.Text exposing (divider)
import Config.Helpers.Converters exposing (toTitleCase)
import Config.Style.Colour.Helpers exposing (ThemeColor(..), getThemeColor)
import Config.Style.Fonts
    exposing
        ( defaultFontSize
        , headerFontSizeBig
        , headerFontSizeMedium
        )
import Config.Style.Transitions
    exposing
        ( hoverFontDarkOrange
        , transitionStyleFast
        )
import Element as E exposing (..)
import Element.Background as B exposing (color)
import Element.Border as D
    exposing
        ( color
        , rounded
        , widthEach
        )
import Element.Font as F exposing (color)
import Element.Input as Input
import Element.Region as Region
import Html exposing (Attribute, Html)
import Html.Attributes
import Html.Events
import Markdown.Block as Block
    exposing
        ( Block
        , Inline
        , ListItem(..)
        , Task(..)
        )
import Markdown.Html
import Markdown.Parser
import Markdown.Renderer
import Ports


articleImage : String -> Element msg
articleImage pic =
    el
        [ centerX
        , width fill
        ]
    <|
        column
            [ E.paddingEach
                { top = 20
                , bottom = 20
                , left = 20
                , right = 20
                }
            ]
            [ image
                [ width fill
                ]
                { src = "/blog/" ++ pic ++ ".jpg", description = "" }
            ]


type Msg
    = ScrollToElement String


renderDeviceMarkdown : String -> Element Msg
renderDeviceMarkdown markdown =
    case renderMarkdown markdown of
        Ok ( toc, renderedMarkdown ) ->
            paragraph []
                [ column
                    [ width fill
                    , centerX
                    , spacing 10
                    ]
                    (tocView toc :: renderedMarkdown)
                ]

        Err error ->
            E.text error


renderDeviceMarkdownGeneric : String -> Element msg
renderDeviceMarkdownGeneric markdown =
    case renderMarkdownGeneric markdown of
        Ok ( toc, renderedMarkdown ) ->
            paragraph []
                [ column
                    [ width fill
                    , centerX
                    , spacing 10
                    ]
                    (tocViewGeneric toc :: renderedMarkdown)
                ]

        Err error ->
            E.text error


renderMarkdown : String -> Result String ( TableOfContents, List (Element Msg) )
renderMarkdown markdown =
    case
        markdown
            |> Markdown.Parser.parse
    of
        Ok okAst ->
            case
                Markdown.Renderer.render elmUiRenderer okAst
            of
                Ok rendered ->
                    Ok ( buildToc okAst, rendered )

                Err errors ->
                    Err errors

        Err error ->
            Err (error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")


renderMarkdownGeneric : String -> Result String ( TableOfContents, List (Element msg) )
renderMarkdownGeneric markdown =
    case
        markdown
            |> Markdown.Parser.parse
    of
        Ok okAst ->
            case
                Markdown.Renderer.render elmUiRendererGeneric okAst
            of
                Ok rendered ->
                    Ok ( buildToc okAst, rendered )

                Err errors ->
                    Err errors

        Err error ->
            Err (error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")


renderDeviceMarkdownNoToc : String -> Element Msg
renderDeviceMarkdownNoToc markdown =
    case renderMarkdownNoToc markdown of
        Ok ( _, renderedMarkdown ) ->
            paragraph []
                [ column
                    [ width fill
                    , centerX
                    , spacing 10
                    ]
                    renderedMarkdown
                ]

        Err error ->
            E.text error


renderDeviceMarkdownNoTocGeneric : String -> Element msg
renderDeviceMarkdownNoTocGeneric markdown =
    case renderMarkdownNoTocGeneric markdown of
        Ok ( _, renderedMarkdown ) ->
            paragraph []
                [ column
                    [ width fill
                    , centerX
                    , spacing 10
                    ]
                    renderedMarkdown
                ]

        Err error ->
            E.text error


renderMarkdownNoToc :
    String
    -> Result String ( TableOfContents, List (Element Msg) ) -- Keep original return type
renderMarkdownNoToc markdown =
    case
        markdown
            |> Markdown.Parser.parse
    of
        Ok okAst ->
            case
                Markdown.Renderer.render elmUiRenderer okAst
            of
                Ok rendered ->
                    Ok ( buildToc okAst, rendered )

                -- Keep building TOC but don't use it
                Err errors ->
                    Err errors

        Err error ->
            Err (error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")


renderMarkdownNoTocGeneric :
    String
    -> Result String ( TableOfContents, List (Element msg) )
renderMarkdownNoTocGeneric markdown =
    case
        markdown
            |> Markdown.Parser.parse
    of
        Ok okAst ->
            case
                Markdown.Renderer.render elmUiRendererGeneric okAst
            of
                Ok rendered ->
                    Ok ( buildToc okAst, rendered )

                Err errors ->
                    Err errors

        Err error ->
            Err (error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")


tocView : TableOfContents -> Element Msg
tocView toc =
    column
        [ alignTop
        , width fill
        , spacing 10
        ]
        [ paragraph
            [ F.bold
            , headerFontSizeBig
            , F.center
            , width fill
            , F.color (getThemeColor TextLightOrange)
            ]
            [ text "TABLE OF CONTENTS" ]
        , column
            [ E.spacing 3
            , defaultFontSize
            , E.width fill
            ]
            (toc
                |> List.indexedMap
                    (\index headingBlock ->
                        row
                            [ E.width fill ]
                            [ el
                                [ E.alignTop
                                , width <| px 30
                                , F.bold
                                , alignRight
                                , alignBottom
                                ]
                                (text (String.fromInt (index + 1) ++ "."))
                            , el
                                [ F.alignLeft
                                , E.width fill
                                , defaultFontSize
                                , alignTop
                                ]
                              <|
                                Input.button
                                    [ F.color (getThemeColor TextLightOrange)
                                    , transitionStyleFast
                                    , hoverFontDarkOrange
                                    , width fill
                                    , paddingEach { top = 0, bottom = 0, left = 0, right = 0 }
                                    ]
                                    { onPress = Just (ScrollToElement headingBlock.anchorId)
                                    , label =
                                        el
                                            [ alignLeft ]
                                        <|
                                            text (toTitleCase headingBlock.name)
                                    }
                            ]
                    )
            )
        , el
            [ width fill
            , height fill
            , spacing 20
            , paddingEach
                { top = 0
                , bottom = 0
                , left = 100
                , right = 100
                }
            ]
          <|
            divider
        , el
            []
          <|
            text ""
        ]


tocViewGeneric : TableOfContents -> Element msg
tocViewGeneric toc =
    column
        [ alignTop
        , width fill
        , spacing 10
        ]
        [ paragraph
            [ F.bold
            , headerFontSizeBig
            , F.center
            , width fill
            , F.color (getThemeColor TextLightOrange)
            ]
            [ text "TABLE OF CONTENTS" ]
        , column
            [ E.spacing 3
            , defaultFontSize
            , E.width fill
            ]
            (toc
                |> List.indexedMap
                    (\index headingBlock ->
                        row
                            [ E.width fill ]
                            [ el
                                [ E.alignTop
                                , width <| px 30
                                , F.bold
                                , alignRight
                                , alignBottom
                                ]
                                (text (String.fromInt (index + 1) ++ "."))
                            , el
                                [ F.alignLeft
                                , E.width fill
                                , defaultFontSize
                                , alignTop
                                ]
                              <|
                                link
                                    []
                                    { url = "#" ++ headingBlock.anchorId
                                    , label =
                                        el
                                            [ F.color (getThemeColor TextLightOrange)
                                            , transitionStyleFast
                                            , hoverFontDarkOrange
                                            ]
                                        <|
                                            text (toTitleCase headingBlock.name)
                                    }
                            ]
                    )
            )
        , el
            [ width fill
            , height fill
            , spacing 20
            , paddingEach
                { top = 0
                , bottom = 0
                , left = 100
                , right = 100
                }
            ]
          <|
            divider
        , el
            []
          <|
            text ""
        ]


buildToc : List Block -> TableOfContents
buildToc blocks =
    let
        headings =
            gatherHeadings blocks
    in
    headings
        |> List.map Tuple.second
        |> List.map
            (\styledList ->
                { anchorId = styledList |> Block.extractInlineText |> rawTextToId
                , name = styledToString styledList
                , level = 1
                }
            )


styledToString : List Inline -> String
styledToString list =
    list
        |> Block.extractInlineText


gatherHeadings : List Block -> List ( Block.HeadingLevel, List Inline )
gatherHeadings blocks =
    List.filterMap
        (\block ->
            case block of
                Block.Heading level content ->
                    Just ( level, content )

                _ ->
                    Nothing
        )
        blocks


elmUiRenderer : Markdown.Renderer.Renderer (Element Msg)
elmUiRenderer =
    { heading = heading
    , paragraph =
        E.paragraph
            [ E.spacing 3
            , defaultFontSize
            , F.alignLeft
            , width fill
            ]
    , thematicBreak = E.none
    , text = E.text
    , strong =
        \content ->
            E.row
                [ F.bold
                ]
                content
    , emphasis =
        \content ->
            E.row
                [ F.italic
                ]
                content
    , strikethrough =
        \content ->
            E.row
                [ F.strike
                ]
                content
    , codeSpan = code
    , link =
        \{ title, destination } body ->
            E.newTabLink
                [ width fill ]
                { url = destination
                , label =
                    E.paragraph
                        [ F.color (getThemeColor TextLightOrange)
                        , defaultFontSize
                        , transitionStyleFast
                        , hoverFontDarkOrange
                        ]
                        body
                }
    , hardLineBreak = Html.br [] [] |> E.html
    , image =
        \image ->
            case image.title of
                Just title ->
                    el
                        [ width fill ]
                    <|
                        column
                            [ E.centerX
                            , E.centerY
                            , width fill
                            , E.paddingEach
                                { top = 0
                                , bottom = 10
                                , left = 10
                                , right = 10
                                }
                            ]
                            [ E.image
                                [ E.centerX
                                , width (fill |> maximum 600)
                                ]
                                { src = image.src
                                , description = image.alt
                                }
                            ]

                Nothing ->
                    el
                        [ width fill ]
                    <|
                        column
                            [ E.centerX
                            , E.centerY
                            , width fill
                            , E.paddingEach
                                { top = 3
                                , bottom = 10
                                , left = 10
                                , right = 10
                                }
                            ]
                            [ E.image
                                [ E.centerX
                                , width (fill |> maximum 600)
                                ]
                                { src = image.src
                                , description = image.alt
                                }
                            ]
    , blockQuote =
        \children ->
            E.column
                [ D.widthEach
                    { top = 0
                    , right = 0
                    , bottom = 0
                    , left = 5
                    }
                , D.rounded 10
                , E.paddingEach
                    { top = 13
                    , bottom = 10
                    , left = 10
                    , right = 10
                    }
                , D.color (getThemeColor TextLightOrange)
                , B.color (getThemeColor BackgroundLightGrey)
                , defaultFontSize
                , width fill
                , spacing 10
                ]
                children
    , unorderedList =
        \items ->
            E.column
                [ E.spacing 10
                , defaultFontSize
                ]
                (items
                    |> List.map
                        (\(ListItem task children) ->
                            E.row
                                [ E.width fill
                                ]
                                [ E.el
                                    [ E.width <| E.px 20
                                    , E.alignTop
                                    , alignRight
                                    ]
                                    (case task of
                                        IncompleteTask ->
                                            Input.defaultCheckbox False

                                        CompletedTask ->
                                            Input.defaultCheckbox True

                                        NoTask ->
                                            E.text "•"
                                    )
                                , E.column
                                    [ E.width fill, F.alignLeft ]
                                    children
                                ]
                        )
                )
    , orderedList =
        \startingIndex items ->
            E.column
                [ E.spacing 10
                , E.width fill
                ]
                (items
                    |> List.indexedMap
                        (\index itemBlocks ->
                            E.row
                                [ E.width fill
                                ]
                                [ E.el
                                    [ E.alignTop
                                    , width <| px 25
                                    , F.bold
                                    , alignRight
                                    , defaultFontSize
                                    ]
                                    (E.text (String.fromInt (index + startingIndex) ++ "."))
                                , E.column
                                    [ alignLeft
                                    , defaultFontSize
                                    , E.width fill
                                    ]
                                    itemBlocks
                                ]
                        )
                )
    , codeBlock = codeBlock
    , html = Markdown.Html.oneOf []
    , table = E.column [ width fill ]
    , tableHeader = E.column [ width fill ]
    , tableBody = E.column [ width fill ]
    , tableRow = E.row [ width fill ]
    , tableHeaderCell =
        \maybeAlignment children ->
            E.paragraph [ width fill ] children
    , tableCell =
        \maybeAlignment children ->
            E.paragraph [ width fill ] children
    }


code : String -> Element msg
code snippet =
    E.el
        [ B.color (getThemeColor BackgroundLightGrey)
        , D.rounded 2
        , E.paddingXY 5 3
        , width fill
        , F.family
            [ F.external
                { url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
                , name = "Source Code Pro"
                }
            ]
        ]
        (E.text snippet)


codeBlock : { body : String, language : Maybe String } -> Element msg
codeBlock details =
    E.el
        [ B.color (getThemeColor BackgroundLightGrey)
        , E.htmlAttribute (Html.Attributes.style "white-space" "pre")
        , width fill
        , E.paddingEach
            { top = 23
            , bottom = 20
            , left = 20
            , right = 20
            }
        , defaultFontSize
        , F.family
            [ F.external
                { url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
                , name = "Source Code Pro"
                }
            ]
        ]
        (E.text details.body)


elmUiRendererGeneric : Markdown.Renderer.Renderer (Element msg)
elmUiRendererGeneric =
    { heading = headingGeneric
    , paragraph =
        E.paragraph
            [ E.spacing 3
            , defaultFontSize
            , F.alignLeft
            , width fill
            ]
    , thematicBreak = E.none
    , text = E.text
    , strong =
        \content ->
            E.row
                [ F.bold
                ]
                content
    , emphasis =
        \content ->
            E.row
                [ F.italic
                ]
                content
    , strikethrough =
        \content ->
            E.row
                [ F.strike
                ]
                content
    , codeSpan = codeGeneric
    , link =
        \{ title, destination } body ->
            E.newTabLink
                [ width fill ]
                { url = destination
                , label =
                    E.paragraph
                        [ F.color (getThemeColor TextLightOrange)
                        , defaultFontSize
                        , transitionStyleFast
                        , hoverFontDarkOrange
                        ]
                        body
                }
    , hardLineBreak = Html.br [] [] |> E.html
    , image =
        \image ->
            case image.title of
                Just title ->
                    el
                        [ width fill ]
                    <|
                        column
                            [ E.centerX
                            , E.centerY
                            , width fill
                            , E.paddingEach
                                { top = 0
                                , bottom = 10
                                , left = 10
                                , right = 10
                                }
                            ]
                            [ E.image
                                [ E.centerX
                                , width (fill |> maximum 600)
                                ]
                                { src = image.src
                                , description = image.alt
                                }
                            ]

                Nothing ->
                    el
                        [ width fill ]
                    <|
                        column
                            [ E.centerX
                            , E.centerY
                            , width fill
                            , E.paddingEach
                                { top = 3
                                , bottom = 10
                                , left = 10
                                , right = 10
                                }
                            ]
                            [ E.image
                                [ E.centerX
                                , width (fill |> maximum 600)
                                ]
                                { src = image.src
                                , description = image.alt
                                }
                            ]
    , blockQuote =
        \children ->
            E.column
                [ D.widthEach
                    { top = 0
                    , right = 0
                    , bottom = 0
                    , left = 5
                    }
                , D.rounded 10
                , E.paddingEach
                    { top = 13
                    , bottom = 10
                    , left = 10
                    , right = 10
                    }
                , D.color (getThemeColor TextLightOrange)
                , B.color (getThemeColor BackgroundLightGrey)
                , defaultFontSize
                , width fill
                , spacing 10
                ]
                children
    , unorderedList =
        \items ->
            E.column
                [ E.spacing 10
                , defaultFontSize
                ]
                (items
                    |> List.map
                        (\(ListItem task children) ->
                            E.row
                                [ E.width fill
                                ]
                                [ E.el
                                    [ E.width <| E.px 20
                                    , E.alignTop
                                    , alignRight
                                    ]
                                    (case task of
                                        IncompleteTask ->
                                            Input.defaultCheckbox False

                                        CompletedTask ->
                                            Input.defaultCheckbox True

                                        NoTask ->
                                            E.text "•"
                                    )
                                , E.column
                                    [ E.width fill, F.alignLeft ]
                                    children
                                ]
                        )
                )
    , orderedList =
        \startingIndex items ->
            E.column
                [ E.spacing 10
                , E.width fill
                ]
                (items
                    |> List.indexedMap
                        (\index itemBlocks ->
                            E.row
                                [ E.width fill
                                ]
                                [ E.el
                                    [ E.alignTop
                                    , width <| px 25
                                    , F.bold
                                    , alignRight
                                    , defaultFontSize
                                    ]
                                    (E.text (String.fromInt (index + startingIndex) ++ "."))
                                , E.column
                                    [ alignLeft
                                    , defaultFontSize
                                    , E.width fill
                                    ]
                                    itemBlocks
                                ]
                        )
                )
    , codeBlock = codeBlockGeneric
    , html = Markdown.Html.oneOf []
    , table = E.column [ width fill ]
    , tableHeader = E.column [ width fill ]
    , tableBody = E.column [ width fill ]
    , tableRow = E.row [ width fill ]
    , tableHeaderCell =
        \maybeAlignment children ->
            E.paragraph [ width fill ] children
    , tableCell =
        \maybeAlignment children ->
            E.paragraph [ width fill ] children
    }


codeGeneric : String -> Element msg
codeGeneric snippet =
    E.el
        [ B.color (getThemeColor BackgroundLightGrey)
        , D.rounded 2
        , E.paddingXY 5 3
        , width fill
        , F.family
            [ F.external
                { url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
                , name = "Source Code Pro"
                }
            ]
        ]
        (E.text snippet)


codeBlockGeneric : { body : String, language : Maybe String } -> Element msg
codeBlockGeneric details =
    E.el
        [ B.color (getThemeColor BackgroundLightGrey)
        , E.htmlAttribute (Html.Attributes.style "white-space" "pre")
        , width fill
        , E.paddingEach
            { top = 23
            , bottom = 20
            , left = 20
            , right = 20
            }
        , defaultFontSize
        , F.family
            [ F.external
                { url = "https://fonts.googleapis.com/css?family=Source+Code+Pro"
                , name = "Source Code Pro"
                }
            ]
        ]
        (E.text details.body)


headingGeneric : { level : Block.HeadingLevel, rawText : String, children : List (Element msg) } -> Element msg
headingGeneric { level, rawText, children } =
    column [ width fill, spacing 20 ]
        [ case level of
            Block.H1 ->
                divider

            _ ->
                none
        , E.paragraph
            [ case level of
                Block.H1 ->
                    headerFontSizeBig

                Block.H2 ->
                    headerFontSizeMedium

                _ ->
                    defaultFontSize
            , F.bold
            , case level of
                Block.H1 ->
                    F.center

                _ ->
                    F.alignLeft
            , width fill
            , F.color (getThemeColor TextLightOrange)
            , Region.heading (Block.headingLevelToInt level)
            , E.htmlAttribute
                (Html.Attributes.attribute "name" (rawTextToId rawText))
            , E.htmlAttribute
                (Html.Attributes.id (rawTextToId rawText))
            ]
            children
        ]


heading : { level : Block.HeadingLevel, rawText : String, children : List (Element Msg) } -> Element Msg
heading { level, rawText, children } =
    column [ width fill, spacing 20 ]
        [ case level of
            Block.H1 ->
                divider

            _ ->
                none
        , E.paragraph
            [ case level of
                Block.H1 ->
                    headerFontSizeBig

                Block.H2 ->
                    headerFontSizeMedium

                _ ->
                    defaultFontSize
            , F.bold
            , case level of
                Block.H1 ->
                    F.center

                _ ->
                    F.alignLeft
            , width fill
            , F.color (getThemeColor TextLightOrange)
            , Region.heading (Block.headingLevelToInt level)
            , E.htmlAttribute
                (Html.Attributes.attribute "name" (rawTextToId rawText))
            , E.htmlAttribute
                (Html.Attributes.id (rawTextToId rawText))
            ]
            children
        ]


rawTextToId rawText =
    rawText
        |> String.split " "
        -- |> Debug.log "split"
        |> String.join "-"
        -- |> Debug.log "joined"
        |> String.toLower



--  Types


type alias TableOfContents =
    List { anchorId : String, name : String, level : Int }
