module Layouts.Navbar exposing (Model, Msg, Props, layout)

import Config.Data.Identity exposing (pageNames)
import Config.Style.Colour.Helpers exposing (colourTheme)
import Config.Style.Fonts
    exposing
        ( defaultFontSize
        , paragraphSpacing
        , spartanFont
        )
import Config.Style.Glow exposing (glowDeepDarkGreyNavbar)
import Config.Style.Icons.Icons
    exposing
        ( circleDots
        , circleX
        , contact
        , debate
        , discord
        , donate
        , gitlab
        , home
        , hyperBlog
        , interviews
        , journal
        , leaving
        , line
        , lock
        , mastodon
        , nutriDex
        , services
        , source
        , twitter
        , upRootLarge
        , upRootMedium
        , upRootSmall
        , video
        )
import Config.Style.Icons.Types as TySvg exposing (..)
import Config.Style.Transitions
    exposing
        ( hoverFontLightOrange
        , specialNavbarTransition
        , transitionStyleFast
        , transitionStyleMedium
        , transitionStyleSlow
        )
import Effect exposing (Effect)
import Element as E exposing (..)
import Element.Background as B
import Element.Border as D
import Element.Events as Events
import Element.Font as F
import Element.Region exposing (description)
import Html exposing (Html)
import Html.Attributes as H
    exposing
        ( class
        , style
        )
import Layout exposing (Layout)
import Maybe.Extra
import Route exposing (Route)
import Route.Path as Path
import Shared
import Shared.Msg
import Svg.Attributes as SvgAttr
import View exposing (View)


type alias Props =
    {}


layout : Props -> Shared.Model -> Route () -> Layout () Model Msg contentMsg
layout _ s r =
    Layout.new
        { init = init s
        , update = update
        , view = view r s
        , subscriptions = \_ -> Sub.none
        }



-- MODEL


type alias Model =
    { isNavbarExpanded : Bool }


init : Shared.Model -> () -> ( Model, Effect.Effect Msg )
init shared _ =
    ( { isNavbarExpanded = shared.isNavbarExpanded }
    , Effect.none
    )



-- UPDATE


type Msg
    = ReplaceMe
    | ToggleNavbarExpansion
    | ToggleLanguage


update : Msg -> Model -> ( Model, Effect.Effect Msg )
update msg model =
    case msg of
        ReplaceMe ->
            ( model
            , Effect.none
            )

        ToggleLanguage ->
            ( model
            , Effect.toggleLanguage
            )

        ToggleNavbarExpansion ->
            ( { model | isNavbarExpanded = not model.isNavbarExpanded }
            , Effect.toggleNavbarExpansion
            )


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none



-- VIEW


view : Route () -> Shared.Model -> { toContentMsg : Msg -> contentMsg, content : View.View contentMsg, model : Model } -> View.View contentMsg
view route shared { toContentMsg, content, model } =
    { title = "uRN :: " ++ content.title
    , attributes =
        [ B.color colourTheme.backgroundDarkGrey
        , F.color colourTheme.textLightGrey
        , F.family [ spartanFont ]
        , height fill
        ]
    , element =
        navbarContainer
            { route = route
            , sharedModel = shared
            , model = model
            , contentMessage = toContentMsg ToggleNavbarExpansion
            , languageSelectorMessage = toContentMsg ToggleLanguage
            , content = content
            }
            (case shared.device.class of
                Phone ->
                    topbar

                Tablet ->
                    topbar

                _ ->
                    sidebar
            )
    }


languageSelector : contentMsg -> Element contentMsg
languageSelector m =
    el
        [ alignRight
        , Events.onClick m
        ]
    <|
        none


navbarContainer : NavbarInput contentMsg -> NavbarMaker contentMsg -> Element contentMsg
navbarContainer input maker =
    el
        [ height fill
        , inFront <| maker input
        , inFront <| languageSelector input.languageSelectorMessage
        , paddingEach <|
            (\( top, left ) ->
                { top = top
                , right = 0
                , bottom = 0
                , left = left
                }
            )
                (case input.sharedModel.device.class of
                    Phone ->
                        ( barReservedRegion.topbar, 0 )

                    Tablet ->
                        ( barReservedRegion.topbar, 0 )

                    _ ->
                        ( 0, barReservedRegion.sidebar )
                )
        , width fill
        ]
    <|
        el
            [ height fill
            , width fill
            , scrollbarY
            , E.htmlAttribute (H.id "scroll-container")
            ]
            input.content.element


barReservedRegion : { sidebar : number, topbar : number }
barReservedRegion =
    { sidebar = 70
    , topbar = 60
    }


bar : NavbarInput contentMsg -> NavbarLogoMaker contentMsg -> List (Attribute contentMsg) -> Element contentMsg
bar input logo attr =
    column
        ([ B.color colourTheme.backgroundDarkGrey
         , transitionStyleMedium
         ]
            ++ attr
        )
    <|
        [ logo input
        , items input
        , footerItems input
        ]


topbar : NavbarInput contentMsg -> Element contentMsg
topbar input =
    bar input
        topbarLogo
        [ height <|
            px <|
                if input.model.isNavbarExpanded then
                    input.sharedModel.height

                else
                    barReservedRegion.topbar
        , width fill
        , D.widthEach
            { bottom = 1
            , top = 0
            , left = 0
            , right = 0
            }
        , D.color colourTheme.textDarkOrange
        ]


topbarLogo : NavbarInput contentMsg -> Element contentMsg
topbarLogo input =
    let
        svgFormat =
            { elementAttributes =
                [ centerX
                , centerY
                , Events.onClick input.contentMessage
                , transitionStyleSlow
                ]
            , sharedModel = input.sharedModel
            , svgAttributes = [ SvgAttr.width "30" ]
            }
    in
    row
        ([ height <| px barReservedRegion.topbar
         , transitionStyleMedium
         , width fill
         ]
            ++ (if input.model.isNavbarExpanded then
                    [ B.color colourTheme.backgroundDarkGrey ]

                else
                    []
               )
        )
    <|
        [ link
            [ pointer ]
            { url = Path.toString Path.Home_
            , label =
                el [ paddingXY 10 0, width <| px 250 ] <| html upRootLarge
            }
        , el
            [ height <| px 50
            , width <| px 40
            , alignRight
            , centerY
            , moveUp 5
            ]
          <|
            -- (if input.model.isNavbarExpanded then
            column [ centerY ]
                [ line
                    (if input.model.isNavbarExpanded then
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , moveDown 13
                            , rotate (degrees 45)
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }

                     else
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }
                    )
                , line
                    (if input.model.isNavbarExpanded then
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , moveUp 22
                            , transparent True
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }

                     else
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , moveUp 22
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }
                    )
                , line
                    (if input.model.isNavbarExpanded then
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , rotate (degrees -45)
                            , moveUp 56
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }

                     else
                        { elementAttributes =
                            [ centerX
                            , centerY
                            , moveUp 44
                            , Events.onClick input.contentMessage
                            , transitionStyleSlow
                            ]
                        , sharedModel = input.sharedModel
                        , svgAttributes = [ SvgAttr.width "30" ]
                        }
                    )
                ]
        ]


sidebar : NavbarInput contentMsg -> Element contentMsg
sidebar input =
    bar input
        sidebarLogo
        [ Events.onMouseEnter <| input.contentMessage
        , Events.onMouseLeave <| input.contentMessage
        , height fill
        , htmlAttribute <| style "overflow" "hidden"
        , htmlAttribute <| style "z-index" "2"
        , D.widthEach
            { bottom = 0
            , top = 0
            , left = 0
            , right = 3
            }
        , glowDeepDarkGreyNavbar
        , D.color colourTheme.textDarkOrange
        , if input.model.isNavbarExpanded then
            width <| px 225

          else
            width <| px barReservedRegion.sidebar
        ]


sidebarLogo : NavbarInput contentMsg -> Element contentMsg
sidebarLogo input =
    let
        logo : Element msg
        logo =
            el
                [ width <| px 40
                , transitionStyleMedium
                , if input.model.isNavbarExpanded then
                    htmlAttribute (style "transform" "rotate(360deg)")

                  else
                    htmlAttribute (style "transform" "rotate(0deg)")
                ]
            <|
                html upRootSmall

        text : Element msg
        text =
            el
                ([ centerY
                 , transitionStyleMedium
                 , width <| px 145
                 ]
                    ++ (if input.model.isNavbarExpanded then
                            []

                        else
                            [ transparent True ]
                       )
                )
            <|
                html upRootLarge
    in
    el
        [ transitionStyleMedium
        , height <| px 60
        , width fill
        ]
    <|
        el
            [ alignRight
            , centerY
            ]
        <|
            el
                [ transitionStyleMedium
                , onLeft text
                , paddingEach
                    { top = 0
                    , right = 12
                    , bottom = 0
                    , left = 12
                    }
                , width fill
                ]
                logo


items : NavbarInput contentMsg -> Element contentMsg
items input =
    let
        navbarUnfucker : List (Attr () msg)
        navbarUnfucker =
            [ transparent True
            , htmlAttribute (style "position" "absolute")
            , htmlAttribute (style "z-index" "-10")
            , htmlAttribute (style "opacity" "0")
            , htmlAttribute (style "pointer-events" "none")
            , htmlAttribute (style "visibility" "hidden")
            ]
    in
    column
        [ height fill
        , width fill
        ]
    <|
        List.map
            (\x ->
                el
                    ([ width fill
                     , transitionStyleMedium
                     ]
                        ++ (if input.model.isNavbarExpanded then
                                case input.sharedModel.device.class of
                                    _ ->
                                        [ transparent False ]

                            else
                                case input.sharedModel.device.class of
                                    Phone ->
                                        navbarUnfucker

                                    Tablet ->
                                        navbarUnfucker

                                    _ ->
                                        [ transparent False ]
                           )
                    )
                <|
                    makeItem input
                        { icon = x.icon
                        , isCurrent = x.isCurrent
                        , isNewTabLink = x.isNewTabLink
                        , isSubscriberOnly = x.isSubscriberOnly
                        , name = x.name
                        , sharedModel = input.sharedModel
                        , url = x.url
                        }
            )
            [ { icon = home
              , isCurrent = input.route.path == Path.Home_
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageHome
              , url = Path.toString Path.Home_
              }
            , { icon = services
              , isCurrent = input.route.path == Path.Services
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageServices
              , url = Path.toString Path.Services
              }
            , { icon = hyperBlog
              , isCurrent = input.route.path == Path.Blog
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageHyperBlog
              , url = Path.toString Path.Blog
              }

            -- , { icon = journal
            --   , isCurrent = input.route.path == Path.Journal
            --   , isNewTabLink = False
            --   , isSubscriberOnly = False
            --   , name = String.toUpper pageNames.pageJournal
            --   , url = Path.toString Path.Journal
            --   }
            , { icon = video
              , isCurrent = False
              , isNewTabLink = True
              , isSubscriberOnly = False
              , name = String.toUpper "Video"
              , url = "https://www.youtube.com/@upRootNutrition"
              }
            , { icon = source
              , isCurrent = False
              , isNewTabLink = True
              , isSubscriberOnly = False
              , name = String.toUpper "Source"
              , url = "https://source.uprootnutrition.com/upRootNutrition/website"
              }
            , { icon = debate
              , isCurrent = input.route.path == Path.Debate
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageDebate
              , url = Path.toString Path.Debate
              }
            , { icon = nutriDex
              , isCurrent = input.route.path == Path.Nutridex
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageNutriDex
              , url = Path.toString Path.Nutridex
              }
            , { icon = interviews
              , isCurrent = input.route.path == Path.Interviews
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageInterviews
              , url = Path.toString Path.Interviews
              }
            , { icon = donate
              , isCurrent = input.route.path == Path.Donate
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageDonate
              , url = Path.toString Path.Donate
              }
            , { icon = contact
              , isCurrent = input.route.path == Path.Contact
              , isNewTabLink = False
              , isSubscriberOnly = False
              , name = String.toUpper pageNames.pageContact
              , url = Path.toString Path.Contact
              }
            ]


makeItemLogic : NavbarInput contentMsg -> RowInput contentMsg -> Element contentMsg
makeItemLogic input route =
    if input.model.isNavbarExpanded then
        case input.sharedModel.device.class of
            _ ->
                makeItem input route

    else
        case input.sharedModel.device.class of
            Phone ->
                el [] none

            Tablet ->
                el [] none

            _ ->
                makeItem input route


makeItem : NavbarInput contentMsg -> RowInput contentMsg -> Element contentMsg
makeItem input route =
    (if route.isNewTabLink then
        newTabLink

     else
        link
    )
        [ width fill ]
        { label =
            row
                ([ mouseOver
                    (if route.isCurrent then
                        []

                     else
                        [ B.color colourTheme.backgroundLightGrey
                        , F.color colourTheme.textLightOrange
                        ]
                    )
                 , paddingEach
                    { top = 0
                    , right = 0
                    , bottom = 0
                    , left = 23
                    }
                 , spacing 12
                 , transitionStyleMedium
                 , width fill
                 ]
                    ++ (if route.isCurrent then
                            [ B.color colourTheme.backgroundDeepDarkGrey
                            , F.color colourTheme.textLightOrange
                            , transitionStyleMedium
                            ]

                        else
                            []
                       )
                    ++ (case input.sharedModel.device.class of
                            Phone ->
                                [ Events.onClick input.contentMessage ]

                            Tablet ->
                                [ Events.onClick input.contentMessage ]

                            _ ->
                                []
                       )
                )
                [ itemIcon input route
                , itemText input route
                , case route.isNewTabLink of
                    True ->
                        itemLeavingIcon input route

                    False ->
                        none
                ]
        , url = route.url
        }


itemIcon : NavbarInput contentMsg -> RowInput contentMsg -> Element contentMsg
itemIcon input route =
    el
        ([ height <| px 50
         , width <| px 20
         ]
            ++ (if Maybe.Extra.isNothing route.sharedModel.user && route.isSubscriberOnly then
                    [ inFront <|
                        lock
                            { elementAttributes =
                                [ moveDown 19
                                , moveLeft 20
                                , F.color colourTheme.barRed
                                ]
                            , sharedModel = route.sharedModel
                            , svgAttributes = [ SvgAttr.width "12" ]
                            }
                    ]

                else
                    []
               )
        )
    <|
        route.icon
            { elementAttributes =
                [ centerX
                , centerY
                ]
            , sharedModel = route.sharedModel
            , svgAttributes =
                [ SvgAttr.width "30" ]
            }


itemLeavingIcon : NavbarInput contentMsg -> RowInput contentMsg -> Element contentMsg
itemLeavingIcon input route =
    el
        [ height <| px 50
        , width <| px 20
        , E.alignRight
        , paddingXY 10 0
        ]
    <|
        leaving
            { elementAttributes =
                [ E.alignRight
                , E.alignTop
                , centerY
                ]
            , sharedModel = route.sharedModel
            , svgAttributes =
                [ SvgAttr.width "15" ]
            }


itemText : NavbarInput contentMsg -> RowInput contentMsg -> Element contentMsg
itemText input route =
    el
        [ specialNavbarTransition -- This special transition is needed to avoid weird animation sequencing rather in Chrome-based browsers.
        , if input.model.isNavbarExpanded then
            transparent False

          else
            transparent True
        , F.bold
        , paddingEach
            { top = 6
            , right = 0
            , bottom = 3
            , left = 0
            }
        ]
    <|
        text route.name


footerItems : NavbarInput contentMsg -> Element contentMsg
footerItems input =
    row
        ([ scrollbarY
         , height <| px 50
         , transitionStyleMedium
         , centerX
         , width <| px 223
         ]
            ++ (if input.model.isNavbarExpanded then
                    []

                else
                    [ transparent True ]
               )
        )
    <|
        List.map
            (\x ->
                makeFooterIcon input
                    { icon = x.icon
                    , isNewTabLink = x.isNewTabLink
                    , url = x.url
                    , sharedModel = input.sharedModel
                    }
            )
            [ { icon = twitter
              , isNewTabLink = True
              , url = "https://x.com/upRootNutrition"
              }
            , { icon = mastodon
              , isNewTabLink = True
              , url = "https://social.uprootnutrition.com/@nick"
              }
            , { icon = discord
              , isNewTabLink = True
              , url = "https://discord.gg/eeYQ2wJknS"
              }
            ]


footerIcon : FooterInput contentMsg -> Element contentMsg
footerIcon route =
    el
        [ height <| px 50
        , width <| px 20
        , alignBottom
        ]
    <|
        route.icon
            { elementAttributes =
                [ centerX
                , centerY
                ]
            , sharedModel = route.sharedModel
            , svgAttributes =
                [ SvgAttr.width "20" ]
            }


makeFooterIcon : NavbarInput contentMsg -> FooterInput contentMsg -> Element contentMsg
makeFooterIcon input route =
    row [ centerX ]
        [ (if route.isNewTabLink then
            newTabLink

           else
            link
          )
            [ width fill ]
            { label =
                row
                    [ mouseOver
                        [ F.color colourTheme.textLightOrange
                        ]
                    , paddingEach
                        { top = 0
                        , right = 10
                        , bottom = 0
                        , left = 10
                        }
                    , transitionStyleMedium
                    , width fill
                    , F.color colourTheme.textLightGrey
                    ]
                    [ footerIcon route
                    ]
            , url = route.url
            }
        ]



-- Types:


type alias NavbarInput contentMsg =
    { route : Route ()
    , sharedModel : Shared.Model
    , model : Model
    , contentMessage : contentMsg
    , languageSelectorMessage : contentMsg
    , content : View.View contentMsg
    }


type alias NavbarMaker contentMsg =
    NavbarInput contentMsg -> Element contentMsg


type alias NavbarLogoMaker contentMsg =
    NavbarMaker contentMsg


type alias RowInput msg =
    { icon : TySvg.OuterPart msg -> Element msg
    , isCurrent : Bool
    , isNewTabLink : Bool
    , isSubscriberOnly : Bool
    , name : String
    , url : String
    , sharedModel : Shared.Model
    }


type alias FooterInput msg =
    { icon : TySvg.OuterPart msg -> Element msg
    , isNewTabLink : Bool
    , url : String
    , sharedModel : Shared.Model
    }
