for _, v in pairs({"7granddad", "betmma", "honey", "oxy", "maxie", "peppino"}) do
    SMODS.Atlas {
        px = 71,
        py = 95,
        key = "jane" .. v,
        path = Jane.config.texture_pack .. "/j_jane_" .. v .. ".png",
    }
end

for i = 1, 6 do
    SMODS.Sound({key = "grand" .. i, path = "grand_dad" .. i .. ".ogg"})
end

SMODS.Sound({key = "corrupt_milestone", path = "corrupt_milestone.ogg"})
SMODS.Sound({key = "corrupt_untick", path = "corrupt_untick.ogg"})
SMODS.Sound({key = "corrupt_tick", path = "corrupt_tick.ogg"})

local exotic = Cryptid and "cry_exotic" or 4

local food = {
    "j_gros_michel",
    "j_egg",
    "j_ice_cream",
    "j_cavendish",
    "j_turtle_bean",
    "j_diet_cola",
    "j_popcorn",
    "j_ramen",
    "j_selzer",
    "j_cry_pickle",
    "j_cry_chili_pepper",
    "j_cry_oldcandy",
    "j_cry_caramel",
    "j_cry_foodm",
    "j_cry_cotton_candy",
    "j_cry_wrapped",
    "j_cry_candy_cane",
    "j_cry_candy_buttons",
    "j_cry_jawbreaker",
    "j_cry_mellowcreme",
    "j_cry_brittle",
    "j_jane_peppino",
}

local granddad_palette = {
    HEX("155fd9"),
    HEX("ff8170"),
    HEX("ffffff"),
    HEX("6c0700"),
}

local function food_jokers_count()
    if not G.jokers then
        return 0
    end

    local amount = 0

    for _, v in pairs(food) do
        amount = amount + #SMODS.find_card(v)
    end

    return amount
end

local function grand_dad(card)
    if ((Talisman or {}).config_file or {}).disable_anims then
        return
    end

    Jane.q(function()
        card:juice_up(0.5, 0.5)
    end)

    local rnd = math.random(6)
    local obj = card.edition or {}

    Jane.play_sound(
        "jane_grand" .. rnd,
        obj.jane_jumbo and (1 / Jane.config.wee_sizemod) or 1,
        0.5
    )

    Jane.card_status_text(
        card,
        rnd == 2 and "Flintstones?!" or rnd == 6 and "Gruhh- Dad!" or "Grand Dad!",
        nil,
        0.05 * card.T.h,
        granddad_palette[math.random(#granddad_palette)],
        0.6,
        0.6,
        nil,
        nil,
        "bm"
    )
end

local function voucher_count()
    if not G.GAME.used_vouchers then
        return 0
    end

    local count = 0

    for _, v in pairs(G.GAME.used_vouchers) do
        if v then
            count = count + 1
        end
    end

    return count
end

local maxie_quotes = {
    normal = {
        "Hey! I hope we can become great friends together!",
        "Need a paw?",
        "Together as a team!",
        "Mmm... Milk sounds good right about now.",
        "Unlike most other bunnies; I don't like carrots.",
        "Mmm... Mac and Cheese...",
        "I am just sitting here.",
    },
    scared = {
        "A-ah! S-stop it, please!! You're scaring me...!",
        "E-eek! B-be careful!!",
    },
}

local maxie_limit = 25

SMODS.Joker {
    key = "maxie",
    atlas = "janemaxie",
    loc_txt = {
        name = "Maxie",
        text = {
            "{C:attention}+#1# {}booster pack slot#2#",
            "{C:inactive,s:0.75,E:1}#3#{C:red,s:1.5,E:1}#4#",
        },
    },
    config = {extra = {choices = Cryptid and 2 or 1}},
    pos = {x = 0, y = 0},
    sinis = {x = 2, y = 0},
    soul_pos = {x = 1, y = 0},
    cost = 6,
    rarity = 2,
    loc_vars = function(_, _, card)
        return {
            vars = {
                card.ability.extra.choices,
                card.ability.extra.choices == 1 and "" or "s",
                Jane.sinister and "" or pseudorandom_element(maxie_quotes.normal, pseudoseed("MaxieQuotes")),
                Jane.sinister and pseudorandom_element(maxie_quotes.scared, pseudoseed("MaxieQuotes")) or "",
            },
        }
    end,
    calculate = function(_, card, context)
        local min = math.min(card.ability.extra.choices, maxie_limit)
        card.ability.extra.choices = min

        if context.starting_shop then
            for _ = 1, min do
                SMODS.add_booster_to_shop()
            end
        end
    end,
}

function Jane.update_honey()
    if not G.GAME then
        return
    end

    local honey = SMODS.find_card("j_jane_honey")
    local mergeable = {}
    local max = 1

    for _, v in pairs(honey) do
        local level = tonumber(v.ability.extra.level) or 1
        max = math.max(max, level)

        if not mergeable[level] then
            mergeable[level] = v
        elseif level == 1 then
            mergeable[0] = v
        end
    end

    for i = math.min(max, #Jane.rarity_ids - 2), 1, -1 do
        if not mergeable[i] then
            goto continue
        end

        local skip = true

        for j = i - 1, i == 1 and 0 or 1, -1 do
            if not mergeable[j] then
                break
            end

            skip = j > 1
        end

        if skip then
            goto continue
        end

        for j = i - 1, i == 1 and 0 or 1, -1 do
            mergeable[i].sell_cost = mergeable[i].sell_cost + mergeable[j].sell_cost
            mergeable[j].ability.extra.level = "-1"
            mergeable[j]:start_dissolve()
        end

        mergeable[i].ability.extra.level = tostring(tonumber(mergeable[i].ability.extra.level) + 1)
        play_sound("jane_corrupt_milestone", 0.9 ^ (tonumber(mergeable[i].ability.extra.level) - 2))
        ::continue::
    end
end

SMODS.Joker {
    key = "honey",
    atlas = "janehoney",
    loc_txt = {
        name = "Honey{C:dark_edition}#1#",
        text = {
            "{C:attention}#2#{}#3#",
            "#4#cannot appear",
            "#5#{C:attention}#6#",
            "{C:dark_edition}#7#{}#8#{C:inactive,s:0.75,E:1}#9#",
            "{C:inactive,s:0.75,E:1}#10#{C:red,s:1.5,E:1}#11#",
        },
    },
    config = {extra = {level = "1"}}, -- Strings do not get mutated by other mods
    pos = {x = 0, y = 0},
    sinis = {x = 2, y = 0},
    soul_pos = {x = 1, y = 0},
    eternal_compat = false,
    cost = 8,
    rarity = 3,
    loc_vars = function(_, _, card)
        local level = tonumber(card.ability.extra.level)

        local function level_name(i)
            local acc = ""
            local prefixes = {"super", "hyper", "ultra"}

            while i > 0 do
                acc = prefixes[((i - 1) % 3) + 1] .. acc
                i = math.floor(i / 3)
            end

            return #acc == 0 and "Corrupted" or acc:gsub("^%l", string.upper) .. "corrupted"
        end

        local is_corrupted = level > 1
        local exclusions = is_corrupted and "" or Jane.rarity_names[level]
        local separator = level == 2 and " " or (is_corrupted and ", " or "")

        if is_corrupted then
            for i = 1, level do
                exclusions = exclusions .. separator .. (i == level and "and " or "") .. Jane.rarity_names[i]
            end
        end

        return {
            vars = {
                is_corrupted and " (" .. level_name(level - 2) .. ")" or "",
                (exclusions or ""):sub(#separator),
                is_corrupted and "" or " jokers",
                is_corrupted and "jokers " or "",
                is_corrupted and (level >= #Jane.rarity_names - 1 and "Cannot be upgraded." or "") or "Getting another ",
                is_corrupted and "" or "Honey",
                is_corrupted and "" or "corrupts ",
                is_corrupted and "" or "this Joker",
                Jane.sinister and "" or (is_corrupted and "*Her eyes are looking around," or ""),
                Jane.sinister and "" or
                (is_corrupted and "as if she wants to say something...*" or "Buzzzzz! I'll do my best!"),
                Jane.sinister and (is_corrupted and "..." or "S-STOP THAT!! YOU'RE FREAKING ME OOOUT!!!") or "",
            },
        }
    end,
    update = function(_, card, _)
        if card.added_to_deck and card.children.center and card.children.floating_sprite then
            local extra = card.ability.extra or {}
            local y = tonumber(extra.level) > 1 and 1 or 0
            card.children.center:set_sprite_pos({x = 0, y = y})
            card.children.floating_sprite:set_sprite_pos({x = Jane.sinister and 2 or 1, y = y})
        end

        local level = tonumber(card.ability.extra.level)

        if not Jane.sinister and level > 2 then
            card:juice_up(0, math.random() * (level - 2) / #Jane.rarity_ids)
        end
    end,
}

if Cryptid then
    Cryptid.aliases["honey"] = "j_jane_honey"
end

local orig_rarity = SMODS.poll_rarity

function SMODS.poll_rarity(_pool_key, _rand_key)
    local max = 0

    for _, v in pairs(SMODS.find_card("j_jane_honey")) do
        max = v.debuff and max or math.max(max, v.ability.extra.level)
    end

    local rarity = orig_rarity(_pool_key, _rand_key)

    for i = 1, max do
        if rarity == Jane.rarity_ids[i] then
            return Jane.rarity_ids[max + 1] or Jane.rarity_ids[#Jane.rarity_ids]
        end
    end

    return rarity
end

local oxy_quotes = {
    normal = {
        "YOU WILL LOSE",
        "DON'T EVEN TRY",
        "WE WILL STOP YOU",
        "He glares at the blinds with conviction.",
    },
    scared = {
        "...H-how are you doing t-that...?",
        "This is... unsettling...",
        "S-... So much power...",
    },
}

function Jane.oxy(card, removed)
    local extra = card.ability.extra or {}
    local destroyed_steel = 0

    for _, v in pairs(removed or {}) do
        if (v.ability or {}).name == "Steel Card" then
            destroyed_steel = destroyed_steel + 1
        end
    end

    if destroyed_steel > 0 then
        extra.progress = extra.progress + destroyed_steel
        play_sound("jane_corrupt_tick")

        card_eval_status_text(
            card,
            "extra",
            nil,
            nil,
            nil,
            {
                message = (extra.is_corrupted and "+" or "-") .. destroyed_steel,
                colour = extra.is_corrupted and G.C.PURPLE or G.C.GREY,
            }
        )
    end
end

local steel = 1.5

SMODS.Joker {
    key = "oxy",
    atlas = "janeoxy",
    loc_txt = {
        name = "Oxy{C:dark_edition}#1#",
        text = {
            "{C:attention}Scored steel {}cards give",
            "{X:mult,C:white}x#2#{} {C:mult}Mult {}and {X:chips,C:white}x#2#{} {C:chips}Chips",
            "{C:dark_edition,E:1}#3#{}#4#{C:red}#5#{C:attention}#6#",
            "{C:dark_edition,E:1}#7#{}#8#",
            "#9#{C:dark_edition,E:1}#10#",
            "{C:inactive,s:0.75,E:1}#11#{C:red,s:1.5,E:1}#12#",
        },
    },
    config = {extra = {corrupted_steel = 2.5, is_corrupted = false, milestone = 3, progress = 0}},
    pos = {x = 0, y = 0},
    sinis = {x = 2, y = 0},
    soul_pos = {x = 1, y = 0},
    blueprint_compat = true,
    cost = Cryptid and 8 or 20,
    rarity = Cryptid and 3 or 4,
    loc_vars = function(_, info_queue, card)
        info_queue[#info_queue + 1] = G.P_CENTERS.m_steel
        local ability = card.ability.extra or {}
        local milestone = ability.milestone
        local progress = ability.progress
        local is_corrupted = ability.is_corrupted
        local amount = is_corrupted and ability.corrupted_steel or steel
        local effective = is_corrupted and progress or milestone - progress
        local plural = effective == 1 and "" or "s"

        return {
            vars = {
                is_corrupted and " (Corrupted)" or "",
                amount,
                is_corrupted and "Purifies " or "",
                is_corrupted and "in " or "",
                is_corrupted and "" or "Destroying ",
                effective .. (is_corrupted and " round" or " steel card") .. plural,
                is_corrupted and "" or "corrupts ",
                is_corrupted and "Destroying steel cards" or "this Joker",
                is_corrupted and "prolongs the " or "",
                is_corrupted and "corruption" or "",
                Jane.sinister and "" or
                (is_corrupted and pseudorandom_element(oxy_quotes.normal, pseudoseed("OxyQuotes")) or "We all cut close..."),
                Jane.sinister and
                (is_corrupted and pseudorandom_element(oxy_quotes.scared, pseudoseed("OxyQuotes")) or "WHAT ARE YOU DOING DOWN THERE?!?") or
                "",
            },
        }
    end,
    update = function(_, card, _)
        if card.added_to_deck and card.children.center and card.children.floating_sprite then
            local extra = card.ability.extra or {}
            local y = extra.is_corrupted and 1 or 0
            card.children.center:set_sprite_pos({x = 0, y = y})
            card.children.floating_sprite:set_sprite_pos({x = Jane.sinister and 2 or 1, y = y})
        end
    end,
    calculate = function(_, card, context)
        local extra = card.ability.extra or {}
        Jane.oxy(card, context.removed)

        if context.end_of_round and
            extra.progress > 0 and not
            context.individual and not
            context.repetition and not
            context.retrigger_joker then
            play_sound("jane_corrupt_untick")
            extra.progress = extra.progress - 1

            card_eval_status_text(
                card,
                "extra",
                nil,
                nil,
                nil,
                {
                    message = extra.is_corrupted and "-1" or "+1",
                    colour = extra.is_corrupted and G.C.PURPLE or G.C.GREY,
                }
            )
        end

        if not extra.is_corrupting and
            ((extra.progress >= extra.milestone and not extra.is_corrupted) or
                (extra.progress <= 0 and extra.is_corrupted)) then
            extra.is_corrupting = true

            Jane.q(function()
                card:flip()
                play_sound("card1")
            end, 0.1)

            Jane.q(function()
                card:flip()
                card:juice_up(1, 1)
                play_sound("card1")
                play_sound("jane_corrupt_milestone")
                extra.is_corrupted = not extra.is_corrupted
                extra.is_corrupting = nil
            end, 1)
        end

        if context.individual and
            context.cardarea == G.play and
            context.other_card.ability.name == "Steel Card" then
            local amount = extra.is_corrupted and extra.corrupted_steel or steel
            return {x_chips = amount, x_mult = amount, colour = G.C.PURPLE, card = card}, true
        end
    end,
}

if Cryptid then
    Cryptid.aliases["oxy"] = "j_jane_oxy"
end

local operator = Cryptid and "^" or "X"

SMODS.Joker {
    key = "betmma",
    atlas = "janebetmma",
    loc_txt = {
        name = "Betmma",
        text = {
            "{X:dark_edition,C:chips}+" .. operator .. "#1#{C:chips} Chips{} for every",
            "{C:attention}unique Voucher redeemed",
            "{C:inactive}(Currently {X:dark_edition,C:chips}" .. operator .. "#2#{C:inactive})",
        },
    },
    config = {extra = {tet = Cryptid and 0.1 or 0.25}},
    pos = {x = 0, y = 0},
    soul_pos = {x = 1, y = 0},
    blueprint_compat = true,
    cost = Cryptid and 20 or 8,
    rarity = Cryptid and 4 or 3,
    loc_vars = function(_, _, center)
        return {vars = {center.ability.extra.tet, 1 + (voucher_count() * center.ability.extra.tet)}}
    end,
    calculate = function(_, card, context)
        if not context.joker_main then
            return
        end

        local v = voucher_count()

        if v > 0 then
            local num = 1 + (v * card.ability.extra.tet)

            return {
                card = card,
                colour = G.C.jane_RGB,
                message = operator .. number_format(num),
                [Cryptid and "e_chips" or "x_chips"] = num,
            }, true
        end
    end,
}

SMODS.Joker {
    key = "7granddad",
    loc_txt = {
        name = "7 GRAND DAD",
        text = {
            "This Joker has a {C:jane_RGB,E:1}strange",
            "{C:jane_RGB,E:1}reaction {}to scored {C:attention}7{}s",
        },
    },
    config = {},
    pos = {x = 0, y = 0},
    soul_pos = {x = 1, y = 0},
    atlas = "jane7granddad",
    blueprint_compat = true,
    cost = Cryptid and 49 or 7,
    rarity = Cryptid and exotic or 3,
    loc_vars = function(_, _, center)
        return {vars = {center.ability.shopslots}}
    end,
    add_to_deck = function(_, card, _)
        grand_dad(card)
    end,
    remove_from_deck = function(_, card, _)
        grand_dad(card)
    end,
    calculate = function(_, card, context)
        if context.cardarea == G.play then
            local function scj(c)
                return c.cardarea and c.cardarea == G.play and not c.before and not c.after and not c.repetition
            end

            if context.other_card and context.other_card:get_id() == 7 and scj(context) then
                grand_dad(card)
                local palette = granddad_palette[math.random(#granddad_palette)]
                local rnd = pseudorandom(pseudoseed("granddad"), 1, Cryptid and 7 or 5)

                if rnd == 1 then
                    return {
                        message = Cryptid and "+777" or "+77",
                        chips = Cryptid and 777 or 77,
                        colour = palette,
                        card = card,
                    }, true
                elseif rnd == 2 then
                    return {
                        message = Cryptid and "+777 Mult" or "+77 Mult",
                        mult = Cryptid and 777 or 77,
                        colour = palette,
                        card = card,
                    }, true
                elseif rnd == 3 then
                    return {
                        message = "+$7",
                        dollars = 7,
                        colour = palette,
                        card = card,
                    }, true
                elseif rnd == 4 then
                    return {
                        message = Cryptid and "x7" or "x1.77",
                        x_chips = Cryptid and 7 or 1.77,
                        colour = palette,
                        card = card,
                    }, true
                elseif rnd == 5 then
                    return {
                        message = Cryptid and "x7 Mult" or "x1.77 Mult",
                        x_mult = Cryptid and 7 or 1.77,
                        colour = palette,
                        card = card,
                    }, true
                elseif rnd == 6 then
                    return {
                        message = "^1.77",
                        e_chips = 1.77,
                        colour = palette,
                        card = card,
                    }, true
                else
                    return {
                        message = "^1.77 Mult",
                        e_mult = 1.77,
                        colour = palette,
                        card = card,
                    }, true
                end
            end
        end
    end,
}

SMODS.Joker {
    key = "peppino",
    atlas = "janepeppino",
    loc_txt = {
        name = "Peppino Spaghetti",
        text = {
            "{X:dark_edition,C:red}" .. operator .. "2^x{C:red} Mult{} for every",
            "{C:attention}food or Peppino Joker",
            "in your possession",
            "{C:inactive}(Currently {X:dark_edition,C:red}" .. operator .. "#1#{C:red} Mult{C:inactive})",
        },
    },
    pos = {x = 0, y = 0},
    soul_pos = {x = 1, y = 0},
    config = {extra = {base = 2}},
    rarity = exotic,
    blueprint_compat = true,
    cost = Cryptid and 50 or 20,
    loc_vars = function(_, _, card)
        return {vars = {card.ability.extra.base ^ food_jokers_count()}}
    end,
    calculate = function(_, card, context)
        local count = food_jokers_count()

        if context.joker_main and count > 0 then
            return {
                colour = G.C.DARK_EDITION,
                message = operator .. card.ability.extra.base ^ count .. " Mult",
                [Cryptid and "e_mult" or "x_mult"] = card.ability.extra.base ^ count,
            }, true
        end
    end,
}
