module Pages.Debate.Cucklist exposing (Model, Msg, page)

import Config.Data.Identity exposing (pageNames)
import Config.Data.ImageFolders as M
    exposing
        ( ImageFolder(..)
        , imagePathMaker
        )
import Config.Helpers.Cards.Inner.Text
    exposing
        ( detailBodyMaker
        , detailFormat
        , detailSpacing
        , detailTitleLink
        , detailTitleMaker
        , getHoverColours
        , numberedListItem
        )
import Config.Helpers.Cards.Inner.ToolTip
    exposing
        ( ToolTipPosition(..)
        , tooltip
        )
import Config.Helpers.Cards.Outer.Helpers exposing (cardMaker)
import Config.Helpers.Cards.Outer.Types as C exposing (Cardable(..))
import Config.Helpers.Converters exposing (formatName, formatSocial)
import Config.Helpers.Headers.Helpers exposing (headerMaker)
import Config.Helpers.Headers.Records exposing (cuckListHeader)
import Config.Helpers.Headers.Types as R exposing (Headerable(..))
import Config.Helpers.Response
    exposing
        ( pageList
        , topLevelContainer
        )
import Config.Helpers.Viewport exposing (resetViewport)
import Config.Pages.Debate.Cuckery.List exposing (cuckList)
import Config.Pages.Debate.Cuckery.Types
    exposing
        ( Cuck
        , Dodge
        , DodgeDescription(..)
        , DodgeFallacies(..)
        , DoxasticState(..)
        , Evaluation(..)
        )
import Config.Style.Colour.Helpers
    exposing
        ( ThemeColor(..)
        , getThemeColor
        )
import Config.Style.Fonts exposing (defaultFontSize, smallTextFontSize)
import Config.Style.Icons.Icons exposing (copyLink)
import Config.Style.Icons.Types as TySvg
    exposing
        ( InnerPart
        , OuterPart
        )
import Config.Style.Images exposing (ElementSize(..), imageSquareMaker)
import Config.Style.Transitions
    exposing
        ( hoverFontDarkOrange
        , transitionStyleFast
        , transitionStyleSlow
        )
import Effect exposing (Effect)
import Element as E
    exposing
        ( Device
        , DeviceClass(..)
        , Element
        , Orientation(..)
        , alignRight
        , alignTop
        , column
        , el
        , fill
        , focused
        , htmlAttribute
        , newTabLink
        , none
        , paddingEach
        , paddingXY
        , paragraph
        , px
        , rgba
        , row
        , spacing
        , text
        , width
        )
import Element.Background as B exposing (color)
import Element.Border as D
    exposing
        ( color
        , rounded
        , shadow
        )
import Element.Font as F exposing (color)
import Element.Input as Input
import Html.Attributes as H exposing (style)
import Layouts
import Page exposing (Page)
import Ports
import Process
import Route exposing (Route)
import Route.Path as Path
import Shared
import Svg.Attributes as SvgAttr
import Task
import View exposing (View)


page : Shared.Model -> Route () -> Page Model Msg
page shared route =
    Page.new
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view shared
        }
        |> Page.withLayout toLayout


toLayout : Model -> Layouts.Layout Msg
toLayout model =
    Layouts.Navbar {}



-- INIT


type alias Model =
    { hasBeenCopied : List Bool }


init : () -> ( Model, Effect Msg )
init () =
    ( { hasBeenCopied = List.repeat (List.length cuckList) False }
    , Effect.batch
        [ Effect.map
            (\_ -> NoOp)
            (Effect.sendCmd resetViewport)
        , Effect.none
        ]
    )



-- UPDATE


type Msg
    = CopyText String Int
    | ResetCopyState Int
    | NoOp


update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
    let
        urlLinkClickUpdate : Int -> Model
        urlLinkClickUpdate index =
            { model
                | hasBeenCopied =
                    List.take index model.hasBeenCopied
                        ++ (case List.head (List.drop index model.hasBeenCopied) of
                                Just isCLicked ->
                                    [ not isCLicked ]

                                Nothing ->
                                    -- shouldn't happen
                                    []
                           )
                        ++ List.drop (index + 1) model.hasBeenCopied
            }
    in
    case msg of
        CopyText text index ->
            ( urlLinkClickUpdate index
            , Effect.batch
                [ Effect.sendCmd (Ports.copyToClipboard text)
                , Effect.sendCmd (Process.sleep 700 |> Task.perform (\_ -> ResetCopyState index))
                ]
            )

        ResetCopyState index ->
            ( urlLinkClickUpdate index
            , Effect.none
            )

        NoOp ->
            ( model
            , Effect.none
            )



-- SUBSCRIPTIONS


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



-- VIEW


view : Shared.Model -> Model -> View Msg
view shared model =
    { title = "debate (" ++ pageNames.pageCucks ++ ")"
    , attributes = []
    , element = cucksContainer shared model
    }


cucksContainer : Shared.Model -> Model -> Element Msg
cucksContainer shared model =
    topLevelContainer (cucksList shared model)


cucksList : Shared.Model -> Model -> Element Msg
cucksList shared model =
    column
        (case ( shared.device.class, shared.device.orientation ) of
            _ ->
                pageList shared.device
        )
    <|
        List.concat
            [ [ headerMaker (R.CuckList cuckListHeader) ]
            , List.map3
                (\cuck dummy index ->
                    cardMaker shared.device (C.Cuck cuck) (contentList shared model dummy index cuck)
                )
                cuckList
                model.hasBeenCopied
                (List.range 0 (List.length cuckList))
            ]


contentList : Shared.Model -> Model -> Bool -> Int -> Cuck -> List (Element Msg)
contentList shared model isLinkClicked index cuck =
    let
        image : ElementSize -> Element msg
        image size =
            el
                [ alignRight
                , alignTop
                , paddingEach
                    { top = 0
                    , right = 10
                    , bottom = 0
                    , left = 0
                    }
                ]
            <|
                imageSquareMaker shared.device (imagePathMaker M.Cuck cuck.cuckImage) True size
    in
    [ detailFormat row
        [ case ( shared.device.class, shared.device.orientation ) of
            ( Phone, Portrait ) ->
                none

            ( Tablet, Portrait ) ->
                none

            _ ->
                image Big
        , detailFormat column
            [ socialMaker cuck
            , dodgeTitle cuck
            , dodgeMaker shared.device cuck
            , el [ alignRight ] <| copyButton shared model isLinkClicked index cuck
            ]
        ]
    ]


copyButton : Shared.Model -> Model -> Bool -> Int -> Cuck -> Element Msg
copyButton shared model isLinkClicked index cuck =
    Input.button
        [ focused
            [ D.color (rgba 0 0 0 0)
            , D.shadow { blur = 0, color = rgba 0 0 0 0, offset = ( 0, 0 ), size = 0 }
            ]
        ]
        { onPress = Just (CopyText ("https://uprootnutrition.com" ++ Path.toString Path.Debate_Cucklist ++ "#" ++ formatName cuck.cuckImage) index)
        , label =
            el
                (if isLinkClicked then
                    [ transitionStyleSlow
                    , tooltip IsRight "Copied!"
                    , case ( shared.device.class, shared.device.orientation ) of
                        ( Phone, Portrait ) ->
                            B.color (getThemeColor BackgroundDarkGrey)

                        ( Tablet, Portrait ) ->
                            B.color (getThemeColor BackgroundDarkGrey)

                        _ ->
                            B.color (getThemeColor BackgroundDeepDarkGrey)
                    , paddingXY 7 7
                    , D.rounded 10
                    , F.color (getThemeColor TextLightOrange)
                    ]

                 else
                    [ transitionStyleSlow
                    , B.color (getThemeColor Transparent)
                    , paddingXY 7 7
                    , D.rounded 10
                    , F.color (getThemeColor TextLightOrange)
                    ]
                        ++ getHoverColours TextLightOrange
                )
            <|
                copyLink
                    { elementAttributes =
                        []
                    , sharedModel = shared
                    , svgAttributes = [ SvgAttr.width "20" ]
                    }
        }


dodgeMaker : Device -> Cuck -> Element msg
dodgeMaker device cuck =
    column
        [ spacing 10
        , width fill
        ]
    <|
        List.map2 (\x y -> makeDodge device cuck x y)
            cuck.cuckDodges
            (List.range 1 (List.length cuck.cuckDodges))


socialMaker : Cuck -> Element msg
socialMaker cuck =
    newTabLink
        []
        { url = cuck.cuckSocial
        , label =
            detailTitleLink
                TextLightOrange
                (formatSocial cuck.cuckSocial)
        }


dodgeTitle : Cuck -> Element msg
dodgeTitle cuck =
    detailTitleMaker
        TextLightGrey
        "Dodges: "


makeDodge : Device -> Cuck -> Dodge -> Int -> Element msg
makeDodge device cuck dodge index =
    detailFormat row
        [ numberedListItem TextLightGrey index
        , detailFormat column
            (dodgeRows device cuck dodge)
        ]


dodgeWidth =
    width <| px 85


formatProposition : String -> String
formatProposition proposition =
    if proposition == "N/A" then
        proposition

    else
        "\"" ++ proposition ++ "\""


dodgeCounter : Int -> Element msg
dodgeCounter index =
    detailTitleMaker TextLightGrey
        (String.fromInt index ++ ". ")


circumstanceMaker : Cuck -> Dodge -> Element msg
circumstanceMaker cuck dodge =
    newTabLink
        []
        { url = dodge.dodgeLink
        , label = circumstance cuck dodge
        }


circumstance : Cuck -> Dodge -> Element msg
circumstance cuck dodge =
    detailFormat paragraph
        [ detailTitleLink TextLightOrange
            (case dodge.dodgeDescription of
                NoReply ->
                    "Debate invitation extended with no response"

                RanAway ->
                    "Engaged in written debate and ran away when cornered"

                GhostedMe ->
                    "Debate invitation accepted with no follow-up"

                PussiedOut ->
                    "Debate invitation declined"

                InTooDeep ->
                    "Debate invitation accepted and subsequently retracted"

                KillScreen ->
                    "All further debate invitations preemptively declined"

                VagueGesture ->
                    "Chose to gesture vaguely instead of engaging"

                EmptyHanded ->
                    "Engaged in written debate and ran away when pressed for specifics"
            )
        , el [ F.color (getThemeColor TextLightGrey) ] <|
            text "."

        -- , receipts cuck dodge
        ]


receipts : Cuck -> Dodge -> Element msg
receipts cuck dodge =
    row
        [ spacing 3
        , smallTextFontSize
        , paddingEach
            { top = 0
            , right = 0
            , bottom = 0
            , left = 3
            }
        , htmlAttribute (H.style "position" "relative")
        , htmlAttribute (H.style "top" "-5px")
        ]
    <|
        List.indexedMap
            (\index2 link ->
                paragraph
                    [ alignTop
                    , F.color (getThemeColor TextLightOrange)
                    ]
                    [ el
                        [ transitionStyleSlow
                        , hoverFontDarkOrange
                        ]
                        (text (String.fromInt (index2 + 1)))
                    , text ", " |> el [ F.color (getThemeColor TextLightGrey) ]
                    ]
            )
            dodge.dodgeReceipts


infoRow : Device -> String -> Element msg -> Element msg
infoRow device label value =
    detailFormat
        (case ( device.class, device.orientation ) of
            ( Phone, Portrait ) ->
                column

            ( Tablet, Portrait ) ->
                column

            _ ->
                row
        )
        (if String.isEmpty label then
            [ detailBodyMaker TextLightGrey value ]

         else
            [ el
                [ width <| px 75
                , alignTop
                ]
              <|
                detailTitleMaker TextLightGrey label
            , detailBodyMaker TextLightGrey value
            ]
        )


dodgeRows : Device -> Cuck -> Dodge -> List (Element msg)
dodgeRows device cuck dodge =
    [ infoRow device "" (circumstanceMaker cuck dodge)
    , infoRow device "Prop:" (text (formatProposition dodge.dodgeProposition))
    , case dodge.dodgeFallacy of
        Nothing ->
            none

        _ ->
            infoRow device "Fallacy:" (reductioMaker device dodge)
    , infoRow device "Attitude:" (attitudeMaker device dodge)
    , infoRow device "Reason:" (reasonMaker device dodge)
    ]


attitudeMaker : Device -> Dodge -> Element msg
attitudeMaker device dodge =
    detailFormat paragraph
        [ case dodge.dodgeNicksDoxasticState of
            Nothing ->
                paragraph [ F.regular ] [ text "I don't form a doxastic state." ]

            Just Belief ->
                paragraph [ F.regular ]
                    [ text "I lean more toward "
                    , el [ F.bold ] (text "TRUE")
                    , text " than false."
                    ]

            Just Disbelief ->
                paragraph [ F.regular ]
                    [ text "I lean more toward "
                    , text "FALSE" |> el [ F.bold ]
                    , text " than true."
                    ]

            Just Agnostic ->
                el [ F.regular ] (text "I don't form beliefs about this proposition.")
        ]


reductioMaker : Device -> Dodge -> Element msg
reductioMaker device dodge =
    let
        displayFallacy : String -> Element msg
        displayFallacy fallacyText =
            detailFormat paragraph
                [ text fallacyText ]
    in
    case dodge.dodgeFallacy of
        Nothing ->
            none

        Just fallacy ->
            case fallacy of
                SpecificFallacy str ->
                    displayFallacy str

                AppealToNature ->
                    displayFallacy "Appeal to Nature"

                AppealToTradition ->
                    displayFallacy "Appeal to Tradition"

                AppealToIgnorance ->
                    displayFallacy "Appeal to Ignorance"

                AppealFromIncredulity ->
                    displayFallacy "Appeal from Incredulity"

                RedHerring ->
                    displayFallacy "Red Herring"

                BeggingTheQuestion ->
                    displayFallacy "Begging the Question"

                Strawman ->
                    displayFallacy "Strawman"

                Equivocation ->
                    displayFallacy "Equivocation"

                GeneticFallacy ->
                    displayFallacy "Genetic Fallacy"

                MotteAndBailey ->
                    displayFallacy "Motte and Bailey"

                MechanisticMasturbation ->
                    displayFallacy "Mechanistic Masturbation"

                Vaguemongering ->
                    displayFallacy "Vaguemongering"

                VagueHumanity ->
                    displayFallacy "Vague Humanity"

                SelfSealing ->
                    displayFallacy "Self-Sealing Argument Fallacy"


reasonMaker : Device -> Dodge -> Element msg
reasonMaker device dodge =
    let
        reasonText =
            case dodge.dodgeNicksDoxasticReason of
                NoProp ->
                    "There is no proposition to evaluate."

                VagueProp ->
                    "The proposition is too vague to evaluate."

                SpecificPropReason str ->
                    str
    in
    detailFormat paragraph
        [ el [ defaultFontSize ] (text reasonText) ]
