SMODS.Atlas {
    px = 71,
    py = 95,
    key = "janedecks",
    path = Jane.config.texture_pack .. "/b_jane_decks.png",
}

local eternal_text = Cryptid and "Absolute" or "Eternal"

SMODS.Back {
    key = "nitro",
    atlas = "janedecks",
    pos = {x = 1, y = 1},
    loc_txt = {
        name = "Acceleration Deck",
        text = {
            Cryptid and "" or "{C:attention}Ante increases twice{} as strong",
            "After defeating the {C:attention}Boss Blind{},",
            Cryptid and "set {C:attention}ante {}to the {C:attention}next" or "",
            Cryptid and "{C:attention}triangle number {}and create" or "",
            Cryptid and "an {C:spectral,E:1}Empowered Tag" or "create a {C:dark_edition}Negative {C:spectral,E:1}Soul",
        },
    },
    apply = function(_)
        G.GAME.win_ante = Cryptid and G.GAME.win_ante * (G.GAME.win_ante + 1) / 2 or G.GAME.win_ante * 2 - 1
        G.GAME.nitro = true
    end,
    trigger_effect = function(_, args)
        if args.context == "eval" and G.GAME.last_blind and G.GAME.last_blind.boss then
            Jane.q(function()
                Jane.empowered()
                return true
            end)
        end
    end,
}

local function add_rain_world_joker()
    if not G.jokers then
        return true
    end

    local candidates = {
        "j_jane_monk",
        "j_jane_survivor",
        "j_jane_hunter",
        "j_jane_gourmand",
        "j_jane_artificer",
        "j_jane_spearmaster",
        "j_jane_rivulet",
        "j_jane_saint",
        "j_jane_rot",
    }

    local unobtained = {}

    for _, v in pairs(candidates) do
        if not next(SMODS.find_card(v, true)) then
            unobtained[#unobtained + 1] = v
        end
    end

    local chosen = pseudorandom_element(next(unobtained) and unobtained or candidates, pseudoseed("karma_deck"))
    local card = create_card("Joker", G.jokers, nil, nil, nil, nil, chosen, "karma_deck_next")
    card:add_to_deck()
    card:start_materialize()
    G.jokers:emplace(card)
    return true
end

SMODS.Back {
    key = "karma",
    atlas = "janedecks",
    pos = {x = 3, y = 0},
    loc_txt = {
        name = "Karma Deck",
        text = {
            "Start with a {C:legendary}Rain World Joker",
            "Create another when",
            "{C:attention}Boss Blind {}is defeated",
        },
    },
    apply = function(_)
        G.E_MANAGER:add_event(Event({func = add_rain_world_joker}))
    end,
    trigger_effect = function(_, args)
        if args.context == "eval" and G.GAME.last_blind and G.GAME.last_blind.boss then
            add_rain_world_joker()
        end
    end,
}

SMODS.Back {
    key = "mysterious",
    atlas = "janedecks",
    pos = {x = 1, y = 0},
    loc_txt = {
        name = "Mysterious Deck",
        text = {
            "Jokers, consumables, and",
            "playing cards are {C:green,E:1}randomized",
            "when they are added",
            "to your possession",
        },
    },
    apply = function(_)
        G.GAME.mysterious = true

        Jane.q(function()
            save_run()
            return true
        end)
    end,
}

SMODS.Back {
    key = "obsidian",
    atlas = "janedecks",
    pos = {x = 2, y = 1},
    loc_txt = {
        name = "Obsidian Deck",
        text = {
            "{C:attention}Hidden{} cards {C:inactive}(ex. {C:spectral}The Soul{C:inactive})",
            "can {C:attention}appear normally{}",
        },
    },
    apply = function(_)
        G.GAME.obsidian = true
    end,
}

local function apply_orrery()
    Jane.q(function()
        local orrery = {}
        G.GAME.orrery = orrery

        for k, v in pairs(G.GAME.hands) do
            v.mult = 1
            v.chips = 150
            orrery[k] = {chips = v.chips, level = v.level, mult = v.mult}
        end

        save_run()
        return true
    end)
end

SMODS.Back {
    key = "orrery",
    atlas = "janedecks",
    pos = {x = 0, y = 0},
    loc_txt = {
        name = "Orrery Deck",
        text = {
            "{C:attention}Hand stats {}are",
            "always " .. (Cryptid and "{C:cry_ascendant}" or "{C:attention}") .. "equalized",
        },
    },
    apply = function(_)
        apply_orrery()
    end,
}

SMODS.Back {
    key = "tortoise",
    atlas = "janedecks",
    pos = {x = 3, y = 1},
    loc_txt = {
        name = "Tortoise Deck",
        text = {
            "{C:attention}Ante increases",
            "{C:attention}half{} as strong",
        },
    },
    apply = function(_)
        G.GAME.tortoise = true
    end,
}

local function apply_weeck()
    G.GAME.weeck = true

    Jane.q(function()
        local new_card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_wee", "weeck")
        new_card.ability.cry_absolute = true
        new_card.ability.eternal = true
        G.jokers:emplace(new_card)
        local add = {}

        for _, v in pairs(G.playing_cards) do
            if v.base.id == 2 then
                v.ability.cry_absolute = true
                v.ability.eternal = true
                add[#add + 1] = v
            else
                v:start_dissolve(nil, true)
            end
        end

        for _, v in pairs(add) do
            local dupe = copy_card(v)
            dupe:start_materialize()
            dupe:add_to_deck()
            G.hand:emplace(dupe)
            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
            table.insert(G.playing_cards, dupe)
        end

        save_run()
        return true
    end)
end

SMODS.Back {
    key = "weeck",
    atlas = "janedecks",
    pos = {x = 4, y = 1},
    loc_txt = {
        name = "Weeck",
        text = {
            "Start with an {C:purple,E:1}" .. eternal_text,
            "{C:attention}Wee Joker {}and a deck",
            "containing {C:attention}2 {C:purple,E:1}" .. eternal_text,
            "{C:attention}2's {}of {C:attention}each suit",
        },
    },
    apply = function(_)
        apply_weeck()
    end,
}

SMODS.Back {
    key = "omega",
    atlas = "janedecks",
    pos = {x = 5, y = 1},
    loc_txt = {
        name = "Omega Deck",
        text = {
            "Applies the {C:legendary,E:1}upsides",
            "of {C:attention}every Jane deck",
        },
    },
    apply = function(_)
        apply_orrery()

        G.E_MANAGER:add_event(Event({
            func = function()
                local wee = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_wee", "weeck")
                G.jokers:emplace(wee)
                add_rain_world_joker()
                G.GAME.mysterious = true
                G.GAME.tortoise = true
                G.GAME.obsidian = true
                save_run()
                return true
            end,
        }))
    end,
    trigger_effect = function(_, args)
        G.GAME.mysterious = nil

        if args.context == "eval" and G.GAME.last_blind and G.GAME.last_blind.boss then
            add_rain_world_joker()

            Jane.q(function()
                Jane.empowered()
                return true
            end)
        end
    end,
}

local orig_ante = ease_ante

---@diagnostic disable-next-line: lowercase-global
function ease_ante(mod)
    local function next_triangle_number(x)
        local n = (math.sqrt(8 * x + 1) - 1) / 2
        return (n + 1) * (n + 2) / 2
    end

    if G.GAME.nitro then
        mod = Cryptid and
            (G.GAME.round_resets.ante < 0 and -G.GAME.round_resets.ante or
                math.ceil(next_triangle_number(G.GAME.round_resets.ante) - G.GAME.round_resets.ante)) or
            (mod > 0 and mod * 2 or mod)
    end

    if G.GAME.tortoise and mod > 0 then
        local remainder = 0

        if mod % 2 == 1 then
            G.GAME.tortoise_halved = not G.GAME.tortoise_halved
            remainder = G.GAME.tortoise_halved and 0 or 1
        end

        mod = math.floor(mod / 2) + remainder
    end

    orig_ante(mod)
end

local orig_emplace = CardArea.emplace

function CardArea:emplace(card, location, stay_flipped)
    local function randomize(targets, noanim)
        local function go(i)
            return function()
                local c = targets[i]
                c:set_base(pseudorandom_element(G.P_CARDS))

                if pseudorandom(pseudoseed("chancetime")) > 1 / (#G.P_CENTER_POOLS["Enhanced"] + 1) then
                    c:set_ability(pseudorandom_element(G.P_CENTER_POOLS["Enhanced"], pseudoseed("spectral_chance")))
                else
                    c:set_ability(G.P_CENTERS["c_base"])
                end

                local edition_rate = 2
                c:set_edition(poll_edition("standard_edition" .. G.GAME.round_resets.ante, edition_rate, true))
                local seal_rate = 10
                local seal_poll = pseudorandom(pseudoseed("stdseal" .. G.GAME.round_resets.ante))

                if seal_poll > 1 - 0.02 * seal_rate then
                    local seal_type = pseudorandom(pseudoseed("stdsealtype" .. G.GAME.round_resets.ante))
                    local seal_list = {}

                    for k, _ in pairs(G.P_SEALS) do
                        table.insert(seal_list, k)
                    end

                    seal_type = math.floor(seal_type * #seal_list)
                    c:set_seal(seal_list[seal_type])
                else
                    c:set_seal()
                end

                if noanim then
                    c:flip()
                    play_sound("card3", 0.85 + (i - 0.999) / (#G.hand.cards - 0.998) * 0.3, 0.6)
                end

                c:juice_up(0.3, 0.3)
                return true
            end
        end

        if #targets <= 0 then
            return
        end

        if noanim then
            for i = 1, #targets do
                go(i)
            end
        else
            for i = 1, #targets do
                G.E_MANAGER:add_event(Event({
                    trigger = "after",
                    delay = 0.15,
                    func = function()
                        targets[i]:flip()
                        play_sound("card1", 1.15 - (i - 0.999) / (#G.hand.cards - 0.998) * 0.3)
                        targets[i]:juice_up(0.3, 0.3)
                        return true
                    end,
                }))
            end

            delay(0.2)

            for i = 1, #targets do
                G.E_MANAGER:add_event(Event({
                    trigger = "after",
                    delay = 0.1,
                    func = go(i),
                }))
            end
        end
    end

    local function rnd(seed, excluded_flags, pool, ignore_pooling, attempts)
        excluded_flags = excluded_flags or {}
        local selection = "n/a"
        local passes = 0
        local tries = attempts or 500
        local pooling = false

        if (SMODS.Mods.jane or {}).can_load and (G.GAME or {}).obsidian then
            for k, v in ipairs(excluded_flags) do
                if v == "hidden" then
                    table.remove(excluded_flags, k)
                    break
                end
            end
        end

        while true do
            passes = 0
            pooling = false
            tries = tries - 1

            selection = G.P_CENTERS
                [pseudorandom_element(pool or G.P_CENTER_POOLS.Consumeables, pseudoseed(seed or "jane_rnd_mysterious")).key]

            if ignore_pooling then
                pooling = true
            else
                if selection.in_pool and selection:in_pool() then
                    pooling = true
                elseif not selection.in_pool then
                    pooling = true
                end
            end

            for _, v in pairs(excluded_flags) do
                if not selection[v] then
                    passes = passes + 1
                end
            end

            if (pooling and passes >= #excluded_flags) or tries <= 0 then
                return selection
            end
        end
    end

    if G.jokers and
        G.hand and
        G.deck and
        G.consumeables and
        (self == G.jokers or self == G.hand or self == G.deck or self == G.consumeables) and
        G.GAME.mysterious and card.ability and not
        card.ability.mysterious_created and not
        card.created_from_split then
        card.ability.mysterious_created = true
        local cen = card.gc and card:gc()
        if cen then
            if self == G.jokers then
                Jane.q(function()
                    if card then
                        if card.added_to_deck then
                            card:remove_from_deck()
                            card.added_to_deck = nil
                        end

                        card:flip()
                        card:juice_up(0.3, 0.3)
                        play_sound("card1", 1, 0.6)
                    end

                    return true
                end, 0.75)

                delay(0.75)

                Jane.q(function()
                    if card then
                        card:flip()
                        card:juice_up(0.3, 0.3)
                        play_sound("card3", 1, 0.6)
                        card:set_ability(rnd("mysterious_deck_joker", {"no_mysterious"}, G.P_CENTER_POOLS.Joker))

                        if not card.added_to_deck then
                            card:add_to_deck()
                        end
                    end

                    return true
                end, 0.75)
            elseif self == G.consumeables then
                Jane.q(function()
                    if card then
                        if card.added_to_deck then
                            card:remove_from_deck()
                            card.added_to_deck = nil
                        end

                        card:flip()
                        card:juice_up(0.3, 0.3)
                        play_sound("card1", 1, 0.6)
                    end

                    return true
                end, 0.75)

                delay(0.75)

                Jane.q(function()
                    if card then
                        card:flip()
                        card:juice_up(0.3, 0.3)
                        play_sound("card3", 1, 0.6)

                        card:set_ability(
                            rnd("mysterious_deck_consumable", cen.hidden and {} or {"hidden"}, G.P_CENTER_POOLS[cen.set])
                        )

                        if not card.added_to_deck then
                            card:add_to_deck()
                        end
                    end

                    return true
                end, 0.75)
            elseif (card.base or {}).value or (card.base or {}).suit then
                randomize({card})
            end
        end

        Jane.q(function()
            if card and self then
                orig_emplace(self, card, location, stay_flipped)
            end

            return true
        end)
    else
        orig_emplace(self, card, location, stay_flipped)
    end
end
