module Card exposing
    ( CardData
    , CardDetails
    , CardPerformanceData
    , CardPerformanceDistributions
    , CardType(..)
    , ManaColor(..)
    , ManaCost(..)
    , Power(..)
    , alpa
    , alsa
    , calculatePerformanceDistributions
    , gihwr
    , iwd
    , manaCostToSymbol
    , parseManaCost
    , pickRate
    )

import Parser as P exposing ((|.), Parser, Trailing(..))
import Stats exposing (NormalDistribution)


type ManaColor
    = Red
    | Blue
    | Green
    | White
    | Black
    | Colorless


type CardType
    = Creature
    | Instant
    | Sorcery
    | Enchantment
    | Artifact
    | Planeswalker
    | Land
    | Other


type Power
    = ConstantPower Int
    | VariablePower


type alias CardData =
    { details : CardDetails
    , performance : CardPerformanceData
    }


type alias CardDetails =
    { name : String
    , cmc : Int
    , cardType : CardType
    , typeLine : String
    , oracleText : Maybe String
    , power : Maybe Power
    , toughness : Maybe Power
    , colors : List ManaColor
    , manaCost : Maybe (List ManaCost)
    , imageUrl : String
    }


type alias CardPerformanceData =
    { totalTimesSeen : Int
    , totalTimesPicked : Int
    , averagePickPosition : Maybe Float
    , averageSeenPosition : Maybe Float
    , gameInHandWinRate : Maybe Float
    , improvementWhenDrawn : Maybe Float
    }


pickRate : CardData -> Float
pickRate card =
    if card.performance.totalTimesSeen == 0 then
        0

    else
        toFloat card.performance.totalTimesPicked / toFloat card.performance.totalTimesSeen


alsa : CardData -> Maybe Float
alsa card =
    card.performance.averageSeenPosition


alpa : CardData -> Maybe Float
alpa card =
    card.performance.averagePickPosition


gihwr : CardData -> Maybe Float
gihwr card =
    card.performance.gameInHandWinRate


iwd : CardData -> Maybe Float
iwd card =
    card.performance.improvementWhenDrawn


type alias CardPerformanceDistributions =
    { alsa : NormalDistribution
    , alpa : NormalDistribution
    , gihwr : NormalDistribution
    , pickRate : NormalDistribution
    , iwd : NormalDistribution
    }


calculatePerformanceDistributions : List CardData -> CardPerformanceDistributions
calculatePerformanceDistributions cards =
    let
        pickRates =
            List.map pickRate cards

        alsaValues =
            List.filterMap alsa cards

        alpaValues =
            List.filterMap alpa cards

        gihwrValues =
            List.filterMap gihwr cards

        iwdValues =
            List.filterMap iwd cards
    in
    { alsa = Stats.getNormalDistribution alsaValues
    , alpa = Stats.getNormalDistribution alpaValues
    , gihwr = Stats.getNormalDistribution gihwrValues
    , pickRate = Stats.getNormalDistribution pickRates
    , iwd = Stats.getNormalDistribution iwdValues
    }


type ManaCost
    = X
    | Y
    | Color ManaColor
    | ColorPay ManaColor
    | Hybrid ManaColor ManaColor
    | HybridPay ManaColor ManaColor
    | AnyColor Int
    | TwoOrColor ManaColor
    | Tap
    | Pay


parseManaCost : String -> Maybe (List ManaCost)
parseManaCost str =
    let
        p =
            P.sequence
                { start = ""
                , separator = ""
                , end = ""
                , spaces = P.spaces
                , item = manaCostP
                , trailing = Optional
                }
    in
    case P.run p str of
        Ok result ->
            Just result

        Err _ ->
            Nothing


manaCostP : Parser ManaCost
manaCostP =
    let
        mapping =
            [ ( "{X}", X )
            , ( "{Y}", Y )
            , ( "{R}", Color Red )
            , ( "{U}", Color Blue )
            , ( "{G}", Color Green )
            , ( "{W}", Color White )
            , ( "{B}", Color Black )
            , ( "{R/P}", ColorPay Red )
            , ( "{U/P}", ColorPay Blue )
            , ( "{G/P}", ColorPay Green )
            , ( "{W/P}", ColorPay White )
            , ( "{B/P}", ColorPay Black )
            , ( "{R/W}", Hybrid Red White )
            , ( "{R/G}", Hybrid Red Green )
            , ( "{W/U}", Hybrid White Blue )
            , ( "{W/B}", Hybrid White Black )
            , ( "{G/U}", Hybrid Green Blue )
            , ( "{G/W}", Hybrid Green White )
            , ( "{U/B}", Hybrid Blue Black )
            , ( "{U/R}", Hybrid Blue Red )
            , ( "{B/G}", Hybrid Black Green )
            , ( "{B/R}", Hybrid Black Red )
            , ( "{R/W/P}", HybridPay Red White )
            , ( "{R/G/P}", HybridPay Red Green )
            , ( "{W/U/P}", HybridPay White Blue )
            , ( "{W/B/P}", HybridPay White Black )
            , ( "{G/U/P}", HybridPay Green Blue )
            , ( "{G/W/P}", HybridPay Green White )
            , ( "{U/B/P}", HybridPay Blue Black )
            , ( "{U/R/P}", HybridPay Blue Red )
            , ( "{B/G/P}", HybridPay Black Green )
            , ( "{B/R/P}", HybridPay Black Red )
            , ( "{2/W}", TwoOrColor White )
            , ( "{2/U}", TwoOrColor Blue )
            , ( "{2/G}", TwoOrColor Green )
            , ( "{2/R}", TwoOrColor Red )
            , ( "{2/B}", TwoOrColor Black )
            , ( "{T}", Tap )
            , ( "{P}", Pay )
            , ( "{0}", AnyColor 0 )
            , ( "{1}", AnyColor 1 )
            , ( "{2}", AnyColor 2 )
            , ( "{3}", AnyColor 3 )
            , ( "{4}", AnyColor 4 )
            , ( "{5}", AnyColor 5 )
            , ( "{6}", AnyColor 6 )
            , ( "{7}", AnyColor 7 )
            , ( "{8}", AnyColor 8 )
            , ( "{9}", AnyColor 9 )
            , ( "{10}", AnyColor 10 )
            , ( "{11}", AnyColor 11 )
            , ( "{12}", AnyColor 12 )
            , ( "{13}", AnyColor 13 )
            , ( "{14}", AnyColor 14 )
            , ( "{15}", AnyColor 15 )
            ]
    in
    P.oneOf
        (List.map (\( str, manaCost ) -> P.succeed manaCost |. P.keyword str) mapping)


manaCostToSymbol : ManaCost -> String
manaCostToSymbol c =
    case c of
        X ->
            "card-symbol-X"

        Y ->
            "card-symbol-Y"

        Color Colorless ->
            "card-symbol-C"

        Color Red ->
            "card-symbol-R"

        Color Blue ->
            "card-symbol-U"

        Color Green ->
            "card-symbol-G"

        Color White ->
            "card-symbol-W"

        Color Black ->
            "card-symbol-B"

        ColorPay Red ->
            "card-symbol-RP"

        ColorPay Blue ->
            "card-symbol-UP"

        ColorPay Green ->
            "card-symbol-GP"

        ColorPay White ->
            "card-symbol-WP"

        ColorPay Black ->
            "card-symbol-BP"

        Hybrid Red White ->
            "card-symbol-RW"

        Hybrid Red Green ->
            "card-symbol-RG"

        Hybrid White Blue ->
            "card-symbol-WU"

        Hybrid White Black ->
            "card-symbol-WB"

        Hybrid Green Blue ->
            "card-symbol-GU"

        Hybrid Green White ->
            "card-symbol-GW"

        Hybrid Blue Black ->
            "card-symbol-UB"

        Hybrid Blue Red ->
            "card-symbol-UR"

        Hybrid Black Green ->
            "card-symbol-BG"

        Hybrid Black Red ->
            "card-symbol-BR"

        HybridPay Red White ->
            "card-symbol-RWP"

        HybridPay Red Green ->
            "card-symbol-RGP"

        HybridPay White Blue ->
            "card-symbol-WUP"

        HybridPay White Black ->
            "card-symbol-WBP"

        HybridPay Green Blue ->
            "card-symbol-GUP"

        HybridPay Green White ->
            "card-symbol-GWP"

        HybridPay Blue Black ->
            "card-symbol-UBP"

        HybridPay Blue Red ->
            "card-symbol-URP"

        HybridPay Black Green ->
            "card-symbol-BGP"

        HybridPay Black Red ->
            "card-symbol-BRP"

        TwoOrColor White ->
            "card-symbol-2W"

        TwoOrColor Blue ->
            "card-symbol-2U"

        TwoOrColor Green ->
            "card-symbol-2G"

        TwoOrColor Red ->
            "card-symbol-2R"

        TwoOrColor Black ->
            "card-symbol-2B"

        Tap ->
            "card-symbol-T"

        Pay ->
            "card-symbol-P"

        AnyColor n ->
            "card-symbol-" ++ String.fromInt n

        _ ->
            ""
