module Shared exposing
    ( Flags, decoder
    , Model, Msg
    , init, update, subscriptions
    )

{-|

@docs Flags, decoder
@docs Model, Msg
@docs init, update, subscriptions

-}

import Browser.Events as BR exposing (..)
import Config.Style.Colour.Types
    exposing
        ( Theme(..)
        , themeFromString
        , themeToString
        )
import Config.Style.Fonts exposing (FontScale, createFontScale)
import Dict
import Effect exposing (Effect, none)
import Element as E exposing (..)
import Json.Decode exposing (..)
import Ports
import Process
import Route exposing (Route)
import Route.Path
import Shared.Model exposing (..)
import Shared.Msg
import Task



-- FLAGS


type alias Flags =
    { height : Int
    , width : Int
    , baseFontSize : Float
    }


decoder : Json.Decode.Decoder Flags
decoder =
    Json.Decode.map3
        (\height width baseFontSize ->
            { height = height
            , width = width
            , baseFontSize = baseFontSize
            }
        )
        (field "height" int)
        (field "width" int)
        (field "baseFontSize" float)



-- INIT


type alias Model =
    Shared.Model.Model


init : Result Json.Decode.Error Flags -> Route () -> ( Model, Effect Msg )
init flagsResult route =
    ( modelFromFlagsResult flagsResult
    , Effect.sendCmd (Ports.checkAssetsLoaded ())
    )


modelFromFlagsResult : Result Error Flags -> Model
modelFromFlagsResult f =
    case f of
        Ok flags ->
            { device = classifyDevice flags
            , height = flags.height
            , width = flags.width
            , theme = Dark
            , fontScale = createFontScale flags.baseFontSize
            , isLoading = True
            , isFadingOut = False
            }

        Err e ->
            { device =
                classifyDevice
                    { height = 0
                    , width = 0
                    }
            , height = 10
            , width = 10
            , theme = Dark
            , fontScale = createFontScale 16.0
            , isLoading = True
            , isFadingOut = False
            }



-- UPDATE


type alias Msg =
    Shared.Msg.Msg


update : Route () -> Msg -> Model -> ( Model, Effect Msg )
update route msg model =
    case msg of
        Shared.Msg.LoadTheme themeString ->
            ( { model | theme = themeFromString themeString }
            , Effect.none
            )

        Shared.Msg.ToggleTheme ->
            ( model
            , Effect.sendCmd (Ports.saveTheme "toggle")
            )

        Shared.Msg.Resize width height ->
            ( { model
                | device =
                    { height = height
                    , width = width
                    }
                        |> E.classifyDevice
                , height = height
                , width = width
              }
            , Effect.none
            )

        Shared.Msg.LoadingComplete ->
            ( { model | isFadingOut = True }
            , Effect.sendCmd (Process.sleep 600 |> Task.perform (\_ -> Shared.Msg.StartFadeOut))
            )

        Shared.Msg.StartFadeOut ->
            ( { model | isLoading = False, isFadingOut = False }
            , Effect.none
            )



-- SUBSCRIPTIONS


subscriptions : Route () -> Model -> Sub Msg
subscriptions route model =
    Sub.batch
        [ BR.onResize Shared.Msg.Resize
        , Ports.loadTheme Shared.Msg.LoadTheme
        , Ports.assetsLoaded (\_ -> Shared.Msg.LoadingComplete)
        ]
