module Editsc.Model exposing
    ( Model
    , Msg

    , init
    , view
    , update
    , subscriptions
    )

import Browser
import Browser.Events
import Duration exposing (Duration)
import Editsc.Port as Port
import Editsc.Ui as Ui
import Editsc.Viewport as Viewport exposing (Viewport)
import Element exposing (Element)
import Element.Background
import Element.Border
import Html exposing (Html)
import Html.Attributes as Attr
import Json.Decode
import List.NonEmpty
import Task exposing (Task)



type alias Model =
    { panicText : String
    , pageTrail : (Page, List Page)
    , viewport : Viewport
    }


type Page
    = WorldImporter
    | ErrorPopup String


type Msg
    = Panic String
    | FramePassed Duration
    | GoBack
    | ImportWorlds (List Json.Decode.Value)
    | PortEvent (Result Json.Decode.Error Port.Event)
    | ViewportResized Viewport


init : () -> (Model, Cmd Msg)
init _ =
    (
        { panicText = ""
        , pageTrail = List.NonEmpty.singleton <|
            WorldImporter
        , viewport = Viewport.default
        }
    , Task.perform ViewportResized Viewport.get
    )


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    case msg of
        Panic panicText ->
            ( { model | panicText = Debug.log "panic" panicText }
            , Cmd.none
            )
        
        FramePassed duration ->
            ( model
            , Cmd.batch
                [ Task.perform ViewportResized Viewport.get
                ]
            )
        
        GoBack ->
            (
                { model
                | pageTrail = (List.NonEmpty.dropHead >> Maybe.withDefault model.pageTrail) model.pageTrail
                }
            , Cmd.none
            )
        
        ImportWorlds [file] ->
            ( model
            , Port.importWorld file
            )
        
        ImportWorlds _ ->
            model
                |> update (Panic "More than 1 file selected")
        
        PortEvent (Ok event) ->
            case event of
                Port.ErrorPopup explanation ->
                    (
                        { model
                        | pageTrail = model.pageTrail
                            |> List.NonEmpty.cons (ErrorPopup explanation)
                        }
                    , Cmd.none
                    )

        PortEvent (Err decodeError) ->
            model
                |> update (Panic <| "Could not decode to Port.Event: " ++ Debug.toString decodeError)
        
        ViewportResized newViewport ->
            ( { model | viewport = newViewport }
            , Cmd.none
            )


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Browser.Events.onAnimationFrameDelta
            (Duration.milliseconds >> FramePassed)
        , Port.subscription PortEvent
        ]


view : Model -> Browser.Document Msg
view model =
    { title = "EditSC"
    , body =
        [ Element.layoutWith
            { options =
                [ noFocusStyle
                ]
            }
            [ Element.width
                (Element.px model.viewport.width)
            , Element.height
                (Element.px model.viewport.height)
            , Element.inFront
                (panel model)
            ]
            scene
        ]
    }


noFocusStyle : Element.Option
noFocusStyle =
    Element.focusStyle
        { borderColor = Nothing
        , backgroundColor = Nothing
        , shadow = Nothing
        }


scene : Element Msg
scene =
    -- layout test
    Element.el
        [ Element.width Element.fill
        , Element.height Element.fill
        , Element.Background.color
            (Element.rgb 255 0 255)
        ]
        Element.none


panel : Model -> Element Msg
panel model =
    Element.column
        [ Element.padding 12
        , Element.scrollbars
        , Element.spacing 12
        , Element.width (Element.fill |> Element.maximum 224)
        ] <|
        panicSection model.panicText ::
        Ui.section
            [ Ui.row
                [ Ui.button
                    { onPress = GoBack
                    , label = Element.text "Back"
                    }
                , Ui.text (pageTitle <| List.NonEmpty.head model.pageTrail)
                ]
            ] ::
        pageBody model


pageTitle : Page -> String
pageTitle page =
    case page of
        WorldImporter ->
            "Import World"
        
        ErrorPopup _ ->
            "Error"


pageBody : Model -> List (Element Msg)
pageBody model =
    let
        page = List.NonEmpty.head model.pageTrail
    in
    case page of
        WorldImporter ->
            [ Ui.section
                [ Ui.row
                    [ Ui.text ".scworld file"
                    , Ui.filesInput
                        { onSelect = ImportWorlds
                        , label = Element.text "None selected"
                        }
                    ]
                ]
            ]
        
        ErrorPopup explanation ->
            [ Ui.section
                [ Ui.text explanation
                ]
            ]


panicSection : String -> Element Msg
panicSection panicText =
    case panicText of
        "" ->
            Element.none
        
        _ ->
            Ui.section
                [ Element.html <|
                    Html.pre [] [ Html.text panicText ]
                ]
