module Pages.DeckEditor exposing (..)

import Browser
import Browser.Events
import Browser.Navigation
import Deck
import Element as E
import Element.Background as Background
import Element.Events as Events
import Element.Font as Font
import Http
import Paginated
import Route
import Spinner
import Symbol
import UI
import Url
import Url.Builder


type alias Model =
    { navigationKey : Browser.Navigation.Key
    , url : Url.Url
    , device : E.Device
    , spinner : Spinner.Model
    , symbols : Symbol.Table
    , deck : Deck
    }


type Msg
    = ViewportChanged UI.Dimensions
    | SpinnerMsg Spinner.Msg
    | GotDeck (Result Http.Error Deck.Deck)
    | GotSymbols Symbol.Table


type Deck
    = Ready Deck.Deck
    | Loading
    | NotFound
    | Failed


type alias Grouped =
    { creatures : List Deck.Card
    , instants : List Deck.Card
    , sorceries : List Deck.Card
    , enchantments : List Deck.Card
    , lands : List Deck.Card
    }


type alias Group =
    { label : String, cards : List Deck.Card }


groups : List Deck.Card -> List Group
groups cards =
    let
        last : List a -> Maybe a
        last xs =
            List.reverse xs |> List.head

        typeOf : Deck.Card -> String
        typeOf card =
            String.split "—" card.card.typeLine
                |> List.head
                |> Maybe.andThen (\types -> String.words types |> last)
                |> Maybe.withDefault ""

        isA : String -> Deck.Card -> Bool
        isA cardType card =
            typeOf card == cardType

        isEmpty : Group -> Bool
        isEmpty group =
            List.isEmpty group.cards
        gather : String -> String -> Group
        gather groupName typeName =
            List.filter (isA typeName) cards
                |> List.sortBy (\dc ->(dc.card.cmc, dc.card.name))
                |> Group groupName
    in
    List.filter (\l -> not <| isEmpty l)
        [ gather "Creatures" "Creature"
        , gather "Planeswalkers" "Planeswalker"
        , gather "Instants" "Instant"
        , gather "Sorceries" "Sorcery"
        , gather "Enchantments" "Enchantment"
        , gather "Artifacts" "Artifact"
        , gather "Lands" "Land"
        ]


init : Browser.Navigation.Key -> Url.Url -> E.Device -> Symbol.Table -> Int -> ( Model, Cmd Msg )
init key url device symbols deckId =
    ( { navigationKey = key
      , url = url
      , device = device
      , spinner = Spinner.init
      , symbols = symbols
      , deck = Loading
      }
    , getDeck deckId
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ViewportChanged viewport ->
            ( { model
                | device = E.classifyDevice viewport
              }
            , Cmd.none
            )

        SpinnerMsg msg_ ->
            ( { model | spinner = Spinner.update msg_ model.spinner }, Cmd.none )

        GotDeck (Ok deck) ->
            ( { model | deck = Ready deck }, Cmd.none )

        GotDeck (Err _) ->
            ( { model | deck = Failed }, Cmd.none )

        GotSymbols symbols ->
            ( { model | symbols = symbols }, Cmd.none )


viewDeck : Symbol.Table -> Deck.Deck -> E.Element Msg
viewDeck symbols deck =
    let
        viewGroup group =
            E.column [ E.spacing 10 ]
                [ E.paragraph [ Font.heavy ] [ UI.title group.label ]
                , E.wrappedRow [ E.spacing 10 ] <|
                    List.map
                        (\dc ->
                            UI.cardRow
                                { foil = False
                                , subtitle = "x" ++ String.fromInt dc.quantity
                                }
                                [ E.width <| E.px 400, E.clipX, Background.color UI.colors.background ]
                                symbols
                                dc.card
                        )
                        group.cards
                ]
    in
    E.column [ E.height E.fill, E.centerX, E.spacing 5 ] <|
        [ E.paragraph [ Font.heavy, Font.size 24, Font.center ] [ UI.title deck.name ]
        , E.column
            [ E.height E.fill
            , E.spacing 10
            , Background.color UI.colors.sidebar
            , E.scrollbarY
            , E.clipX
            ]
          <|
            List.map viewGroup <|
                groups deck.cards
        ]


view : Model -> E.Element Msg
view model =
    E.column
        [ E.width E.fill
        , E.height E.fill
        ]
        [ case model.deck of
            Ready deck ->
                viewDeck model.symbols deck

            Failed ->
                E.none

            NotFound ->
                E.none

            Loading ->
                E.el [ E.height E.fill, E.centerX ] <|
                    E.html <|
                        Spinner.view UI.manaSpinner
                            model.spinner
        , UI.footer <|
            case model.deck of
                Ready deck ->
                    UI.text <|
                        String.join " "
                            [ String.fromInt (List.sum <| List.map .quantity deck.cards)
                            , "cards"
                            ]

                _ ->
                    E.none
        ]


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Browser.Events.onResize
            (\w h -> ViewportChanged { width = w, height = h })
        , Sub.map SpinnerMsg Spinner.subscription
        ]


getDeck : Int -> Cmd Msg
getDeck deckId =
    Http.get
        { url =
            Url.Builder.absolute
                [ "api", "decks", String.fromInt deckId ]
                []
        , expect = Http.expectJson GotDeck Deck.decode
        }