{
    config,
    lib,
    pkgs,
    ...
}:

let
    inherit (lib) mkOption mkIf types;
    inherit (types) either;

    clamp =
        x: min: max:
        if x < min then
            min
        else if x > max then
            max
        else
            x;

    cfg = config.programs.tetrio-desktop;
in
{
    options.programs.tetrio-desktop = {
        enable = lib.mkEnableOption "tetrio";
        package = lib.mkPackageOption pkgs "tetrio-desktop" { };

        plus = {
            enable = lib.mkEnableOption "tetrio-plus";
            package = lib.mkOption {
                type = types.path;
                description = "The package to use for TETR.IO PLUS";
                default = pkgs.tetrio-plus;
            };

            skin = mkOption {
                type = types.nullOr (
                    types.submodule {
                        options = {
                            package = mkOption {
                                type = types.package;
                                description = "The package to use for the skin";
                                example = "mpkgs.tetrio.skin.simple-connected";
                            };

                            nearest = mkOption {
                                type = types.bool;
                                description = "Force nearest-neighbor scaling";
                                default = false;
                            };
                        };
                    }
                );
                default = null;
                description = "In-game tetrimino skin";
            };

            hideOnStartup = lib.mkOption {
                type = types.bool;
                default = true;
                description = "Disable the TETR.IO PLUS configuration panel showing";
            };
        };
        settings = {
            handling =
                let
                    buffering = types.enum [
                        "off"
                        "hold"
                        "tap"
                    ];
                in
                {

                    auto_repeat_rate = mkOption {
                        type = types.number;
                        apply = x: clamp x 0 5;
                        description = "Automatic Repeat Rate: the speed at which tetrominoes move when holding down movement keys, measured in frames per movement.";
                        default = 2;
                    };
                    delayed_auto_shift = mkOption {
                        type = types.number;
                        apply = x: clamp x 1 20;
                        description = "Delayed Auto Shift: the time between the initial keypress and the start of its automatic repeat movement, measured in frames.";
                        default = 10;
                    };
                    das_cut_delay = mkOption {
                        type = types.number;
                        apply = x: clamp x 0 20;

                        description = "DAS Cut Delay (frames): if not 0, any ongoing DAS movement will pause for a set amount of time after dropping/rotating a piece, measured in frames.";
                        default = 1;
                    };
                    soft_drop_factor = mkOption {
                        type = types.number;
                        apply = x: clamp x 5 41;
                        description = "Soft Drop Factor: the factor with which soft drops change the gravity speed.";
                        default = 6;
                    };
                    prevent_hard_drops = mkOption {
                        type = types.bool;
                        description = "If enabled, when a piece locks on its own, the hard drop key becomes unavailable for a few frames. This prevents accidental hard drops.";
                        default = true;
                    };
                    direction_cancel_das = mkOption {
                        type = types.bool;
                        description = "If enabled, DAS charge is cancelled when you change directions.";
                        default = false;
                    };
                    soft_drop_over_movement = mkOption {
                        type = types.bool;
                        description = "If enabled, at very high speeds soft drop will always take precedence over horizontal movement, for a more consistent game feel.";
                        default = true;
                    };
                    rotation_buffering = mkOption {
                        type = buffering;
                        description = "When to buffer rotations for the next piece (\"hold\": only if you hold the key as the next piece spawns).";
                        default = "tap";
                    };
                    hold_buffering = mkOption {
                        type = buffering;
                        description = "When to buffer holding for the next piece (\"hold\": only if you hold the key as the next piece spawns).";
                        default = "tap";
                    };
                };
            audio =
                let
                    percentage = x: x / 100.0;
                in
                {
                    music = {
                        volume = mkOption {
                            type = types.number;
                            apply = x: percentage (clamp x 0 200);
                            description = "Volume (%) at which BGM and jingles play.";
                            default = 100;
                        };
                        reset_on_retry = mkOption {
                            type = types.bool;
                            apply = x: !x;
                            description = "If enabled, the background music will reset whenever you retry a game.";
                            default = false;
                        };
                        preferences = mkOption {
                            type =
                                with types;
                                attrsOf (enum [
                                    "off"
                                    "--"
                                    "-"
                                    ""
                                    "+"
                                    "++"
                                ]);
                            apply =
                                x:
                                pkgs.lib.mapAttrs (
                                    _: value:
                                    {
                                        "off" = "ban";
                                        "--" = "minmin";
                                        "-" = "min";
                                        "" = "base";
                                        "+" = "plus";
                                        "++" = "plusplus";
                                    }
                                    ."${value}"
                                ) x;
                            default = { };
                        };
                    };
                    sfx = {
                        volume = mkOption {
                            type = types.number;
                            apply = x: percentage (clamp x 0 200);
                            description = "Volume (%) at which sound effects play.";
                            default = 100;
                        };
                        next_pieces = mkOption {
                            type = types.bool;
                            description = "Whether to play a sound effect that signifies the next piece that'll come up.";
                            default = false;
                        };
                        other_players = mkOption {
                            type = types.bool;
                            description = "Whether to hear the sounds of other people playing in Multiplayer.";
                            default = true;
                        };
                        attacks = mkOption {
                            type = types.bool;
                            description = "Whether to hear the sounds of attacks going towards and from you.";
                            default = true;
                        };
                        speed_changes = mkOption {
                            type = types.bool;
                            description = "Whether to hear a sound when your Climb Speed changes in Quick Play.";
                            default = true;
                        };
                    };
                    scroll_adjust_volume = mkOption {
                        type = types.bool;
                        description = "Whether to allow adjusting the volume via scrolling in-game (or everywhere while holding ALT).";
                        default = true;
                    };
                    mute_unfocused = mkOption {
                        type = types.bool;
                        description = "If enabled, the background music will be muted when TETR.IO is minimized or tabbed away.";
                        default = true;
                    };
                    stereo = mkOption {
                        type = types.number;
                        apply = x: percentage (clamp x 0 100);
                        description = "Intensity (%) of stereo effects. 0% -> Centered; 100% -> Directional";
                        default = 50;
                    };
                    disable = mkOption {
                        type = types.bool;
                        description = "If enabled, no audio will ever play. This will speed up the game, with a rather obvious drawback.";
                        default = false;
                    };
                };
            visual =
                let
                    toFloat = x: if builtins.typeOf x == "str" then builtins.fromJSON x else x;
                    percentage =
                        x: min: max:
                        builtins.toString ((clamp (toFloat x) min max) / 100.0);
                in
                {
                    graphics = {
                        pipeline = mkOption {
                            type = types.enum [
                                "compatability"
                                "webgl-1"
                                "webgl-2"
                            ];
                            apply =
                                x:
                                {
                                    "compatability" = "legacy";
                                    "webgl-1" = "webgl1";
                                    "webgl-2" = "webgl2";
                                }
                                ."${x}";
                            description = "The WebGL mode to use for rendering";
                            default = "webgl-2";
                        };
                        tier = mkOption {
                            type = types.enum [
                                "minimal"
                                "low"
                                "medium"
                                "high"
                                "ultra"
                            ];
                            description = "The graphics tier to use for rendering";
                            default = "ultra";
                        };
                        cache = mkOption {
                            type = types.bool;
                            apply = x: if x then "medium" else "low";
                            description = "Whether or not to enable caching of resources";
                            default = true;
                        };
                        particle_count = mkOption {
                            type = with types; either str number;
                            apply = x: percentage x 10 150;
                            description = "How many particles to display (%).";
                            default = 150;
                        };

                        powersave = mkOption {
                            type = types.bool;
                            description = "If enabled, prioritize power saving over performance.";
                            default = false;
                        };
                        low_resolution = mkOption {
                            type = types.bool;
                            description = "If enabled, render blurrier graphics. Not very pretty but helps performance.";
                            default = false;
                        };
                        low_precision_counters = mkOption {
                            type = types.bool;
                            description = "If enabled, don't show as much precision on in-game counters. Speeds up the game significantly.";
                            default = false;
                        };
                    };
                    show_unfocus_warning = mkOption {
                        type = types.bool;
                        description = "If enabled, a warning is shown when TETR.IO is out of focus.";
                        default = true;
                    };
                    action_text = mkOption {
                        type = types.enum [
                            "off"
                            "some"
                            "all"
                        ];
                        description = "Determines how much action text to display when performing special attacks.";
                        default = "some";
                    };
                    board_bounciness = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 200;
                        description = "How much (%) the board reacts when you move pieces around.";
                        default = 40;
                    };
                    damage_shakiness = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 110;
                        description = "How much (%) the board reacts when you receive damage.";
                        default = 100;
                    };
                    grid_opacity = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 110;
                        description = "How visible the grid is (%). 0% makes the grid invisible.";
                        default = 10;
                    };
                    board_opacity = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 110;
                        description = "How visible the board is (%). 0% makes the board invisible.";
                        default = 85;
                    };
                    shadow_opacity = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 110;
                        description = "How visible the shadow piece is (%). 0% makes the shadow piece invisible.";
                        default = 15;
                    };
                    background_opacity = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 100;
                        description = "How visible the background images are. 0% makes the background entirely black.";
                        default = 5;
                    };
                    show_background_in_menus = mkOption {
                        type = types.bool;
                        apply = x: !x;
                        description = "If enabled, do not show the background when in menus. This will majorly improve performance in menus, but you will no longer see the background.";
                        default = false;
                    };
                    board_zoom = mkOption {
                        type = with types; either str number;
                        apply = x: percentage x 0 110;
                        description = "How large the board displays. Values over 100% may cause some elements to not be visible.";
                        default = 100;
                    };
                    spin_board = mkOption {
                        type = types.bool;
                        description = "When enabled, the board reacts to T-Spins by rotating a little with it.";
                        default = true;
                    };
                    fire_meter = mkOption {
                        type = types.bool;
                        description = "If enabled, fill a fire meter when doing well, illuminating boards that have a lot of fire.";
                        default = true;
                    };
                    danger_warning = mkOption {
                        type = types.bool;
                        description = "If enabled, makes the board red and play a warning sound when you're in danger.";
                        default = true;
                    };
                    colored_shadow = mkOption {
                        type = types.bool;
                        description = "If enabled, colors the shadow piece.";
                        default = true;
                    };
                    color_locked_hold_piece = mkOption {
                        type = types.bool;
                        description = "If enabled, the HOLD piece will be grayed out if it may not be used.";
                        default = true;
                    };

                };
            multiplayer = {
                chat = {
                    enable = mkOption {
                        type = types.bool;
                        apply = x: !x;
                        description = "If disabled, chat will be hidden when ingame.";
                        default = true;
                    };
                    filter = mkOption {
                        type = types.bool;
                        description = "If enabled, profanity in chat will be filtered. Note that such filters are never perfect.";
                        default = true;
                    };
                    show_emotes = mkOption {
                        type = types.bool;
                        description = "If enabled, show emotes in chat.";
                        default = true;
                    };
                    show_animated_emotes = mkOption {
                        type = types.bool;
                        description = "If enabled, show animated emotes in chat.";
                        default = true;
                    };
                    invert = mkOption {
                        type = types.bool;
                        description = "If enabled, chat text shows in black (good for light backgrounds).";
                        default = false;
                    };
                    darken = mkOption {
                        type = types.bool;
                        description = "If enabled, show a background behind chat messages when typing.";
                        default = true;
                    };
                };
                notifications =
                    let
                        notification.optional = types.enum [
                            "off"
                            "in-game"
                            "desktop"
                        ];
                        notification.required = types.enum [
                            "in-game"
                            "desktop"
                        ];
                        apply =
                            x:
                            {
                                "off" = "off";
                                "in-game" = "ingame";
                                "desktop" = "both";
                            }
                            ."${x}";
                    in
                    {
                        when = {
                            friend_online = mkOption {
                                type = notification.optional;
                                inherit apply;
                                description = "Notify me when a friend goes online";
                                default = "in-game";
                            };
                            friend_offline = mkOption {
                                type = notification.optional;
                                inherit apply;
                                description = "Notify me when a friend goes offline";
                                default = "off";
                            };
                            friend_dm_recieved = mkOption {
                                type = notification.optional;
                                inherit apply;
                                description = "Notify me when a friend sends me a direct message";
                                default = "desktop";
                            };
                            dm_recieved = mkOption {
                                type = notification.optional;
                                inherit apply;
                                description = "Notify me when a non-friend sends me a direct message";
                                default = "desktop";
                            };
                            room_invite = mkOption {
                                type = notification.required;
                                inherit apply;
                                description = "Notify me when someone invites me to a room";
                                default = "desktop";
                            };
                            other = mkOption {
                                type = notification.required;
                                inherit apply;
                                description = "Other notifications";
                                default = "desktop";
                            };
                        };
                        enable_desktop_notifications = mkOption {
                            type = types.bool;
                            description = "If enabled, show notifications outside of the game.";
                            default = true;
                        };
                        suppress_while_playing = mkOption {
                            type = types.bool;
                            description = "If enabled, unimportant notifications don't show ingame, but will be shown after the game.";
                            default = false;
                        };
                        full_volume = mkOption {
                            type = types.bool;
                            description = "If enabled, notification sounds always play at full volume.";
                            default = true;
                        };
                    };
                hide_room_ids = mkOption {
                    type = types.bool;
                    description = "If enabled, room IDs will not be shown, to protect you from streamsniping.";
                    default = false;
                };
                show_network_warnings = mkOption {
                    type = types.bool;
                    apply = x: !x;
                    description = "If disabled, network warning icons will not be shown.";
                    default = true;
                };
                notify_elim = mkOption {
                    type = types.bool;
                    description = "If enabled, show a popup when you KO someone or get KO'd.";
                    default = true;
                };
                duels_side_by_side = mkOption {
                    type = types.bool;
                    description = "Whether to display a duel side-by-side. This causes your own board to move slightly to the left.";
                    default = true;
                };
                simplify_thumbnails = mkOption {
                    type = types.bool;
                    description = "If enabled, always shows the simpler thumbnails for other players. This increases performance in games between 2 and 8 players, but looks less nice.";
                    default = false;
                };
                animate_super_lobby_background = mkOption {
                    type = types.bool;
                    apply = x: !x;
                    description = "If enabled, the background of Super Lobbies (rooms of 100+ players) animate.";
                    default = true;
                };
                animate_background_in_quickplay = mkOption {
                    type = types.bool;
                    apply = x: !x;
                    description = "If enabled, the background of Quick Play animate.";
                    default = true;
                };
                welcome_guide = mkOption {
                    type = types.bool;
                    description = "If enabled, show the simple guide with the keybinds in multiplayer lobbies.";
                    default = true;
                };
            };
            keep_replay_tools_open = mkOption {
                type = types.bool;
                description = "If enabled, the replay tools do not collapse when you're not using them.";
                default = false;
            };
            skip_login_screen = mkOption {
                type = types.enum [
                    "never"
                    "by-url"
                    "always"
                ];
                apply =
                    x:
                    {
                        "never" = "never";
                        "by-url" = "quickjoin";
                        "always" = "always";
                    }
                    ."${x}";
                description = "When to skip the login screen (\"by-url\": only when joining matches or viewing replays by url)";
                default = "always";
            };
            discord_rpc = mkOption {
                type = types.bool;
                description = "If enabled, show your current activity in Discord.";
                default = true;
            };
            flash_taskbar_icon = mkOption {
                type = types.bool;
                description = "If enabled, the taskbar icon will flash when something important happens.";
                default = true;
            };
            devtools = mkOption {
                type = types.bool;
                description = "If enabled, allow opening the developer toolbox.";
                default = false;
            };
            advertisments.i_support_the_devs.i_cannot_play_with_ads.and_i_really_want_to.disable = mkOption {
                type = types.bool;
                description = "If enabled, most/all third-party ads will not show.";
                default = false;
            };
        };
    };

    config = mkIf cfg.enable (
        lib.mkMerge [
            {
                home.packages = [
                    (cfg.package.override {
                        withTetrioPlus = cfg.plus.enable;
                        tetrio-plus = cfg.plus.package;
                    })
                ];

                home.initialFile.".config/tetrio-desktop/Local Storage/leveldb" = {
                    mode = "0644";
                    source = pkgs.callPackage ./leveldb.nix {
                        value = {
                            handling =
                                let
                                    set = cfg.settings.handling;
                                in
                                {
                                    arr = set.auto_repeat_rate;
                                    das = set.delayed_auto_shift;
                                    dcd = set.das_cut_delay;
                                    sdf = set.soft_drop_factor;
                                    safelock = set.prevent_hard_drops;
                                    cancel = set.direction_cancel_das;
                                    may20g = set.soft_drop_over_movement;
                                    irs = set.rotation_buffering;
                                    ihs = set.hold_buffering;
                                };
                            volume =
                                let
                                    set = cfg.settings.audio;
                                in
                                {
                                    music = set.music.volume;
                                    bgmtweak = set.music.preferences;
                                    sfx = set.sfx.volume;
                                    stereo = set.stereo;
                                    scrollable = set.scroll_adjust_volume;
                                    oof = set.mute_unfocused;
                                    next = set.sfx.next_pieces;
                                    others = set.sfx.other_players;
                                    attacks = set.sfx.attacks;
                                    zenithrank = set.sfx.speed_changes;
                                    disable = set.disable;
                                };
                            video =
                                let
                                    set = cfg.settings.visual;
                                    mul = cfg.settings.multiplayer;
                                in
                                {
                                    actionText = set.action_text;
                                    bounciness = set.board_bounciness;
                                    shakiness = set.damage_shakiness;
                                    gridopacity = set.grid_opacity;
                                    boardopacity = set.board_opacity;
                                    shadowopacity = set.shadow_opacity;
                                    zoom = set.board_zoom;
                                    sidebyside = mul.duels_side_by_side;
                                    spin = set.spin_board;
                                    kos = mul.notify_elim;
                                    siren = set.danger_warning;
                                    colorshadow = set.colored_shadow;

                                    graphics = set.graphics.tier;
                                    caching = set.graphics.cache;
                                    webgl = set.graphics.pipeline;
                                    particles = set.graphics.particle_count;
                                    background = set.background_opacity;
                                    powersave = set.graphics.powersave;
                                    lowres = set.graphics.low_resolution;
                                    lowrescounters = set.graphics.low_precision_counters;
                                    alwaystiny = mul.simplify_thumbnails;
                                    nosuperlobbyanim = mul.animate_super_lobby_background;
                                    nozenithanim = mul.animate_background_in_quickplay;
                                    nobg = set.show_background_in_menus;
                                    chatfilter = mul.chat.filter;
                                    nochat = mul.chat.enable;
                                    hideroomids = mul.hide_room_ids;
                                    emotes = mul.chat.show_emotes;
                                    emotes_anim = mul.chat.show_animated_emotes;
                                    invert = mul.chat.invert;
                                    chatbg = mul.chat.darken;
                                    replaytoolsnocollapse = cfg.settings.keep_replay_tools_open;
                                    hidenetwork = mul.show_network_warnings;
                                    focuswarning = set.show_unfocus_warning;
                                    guide = mul.welcome_guide;

                                    desktopnotifications = mul.notifications.enable_desktop_notifications;
                                };
                            notifications =
                                let
                                    set = cfg.settings.multiplayer.notifications;
                                in
                                {
                                    suppress = set.suppress_while_playing;
                                    forcesound = set.full_volume;
                                    online = set.when.friend_online;
                                    offline = set.when.friend_offline;
                                    dm = set.when.friend_dm_recieved;
                                    dm_pending = set.when.dm_recieved;
                                    invite = set.when.room_invite;
                                    other = set.when.other;
                                };
                            electron = {
                                loginskip = cfg.settings.skip_login_screen;
                                adblock =
                                    cfg.settings.advertisments.i_support_the_devs.i_cannot_play_with_ads.and_i_really_want_to.disable;
                                taskbarflash = cfg.settings.flash_taskbar_icon;
                                autoupdate = false;
                                anglecompat = false;
                                presence = cfg.settings.discord_rpc;
                                devtools = cfg.settings.devtools;
                            };
                        };
                    };
                    recursive = true;
                };
            }
            (mkIf (cfg.plus.enable) {
                home.file.".config/tetrio-desktop/tetrioplus/tpkey-tetrioPlusEnabled.json" = {
                    text = ''
                        { "value": true }
                    '';
                    force = true;
                };
                home.file.".config/tetrio-desktop/tetrioplus/tpkey-hideTetrioPlusOnStartup.json" = {
                    text = ''
                        { "value": ${lib.trivial.boolToString cfg.plus.hideOnStartup} }
                    '';
                    force = true;
                };
            })
            (mkIf (cfg.plus.enable && cfg.plus ? skin) {
                home.file.".config/tetrio-desktop/tetrioplus/tpkey-skin.json" = {
                    source = cfg.plus.skin.package;
                    force = true;
                };
                home.file.".config/tetrio-desktop/tetrioplus/tpkey-forceNearestScaling.json" = {
                    text = ''
                        			{ "value": ${lib.trivial.boolToString cfg.plus.skin.nearest} }
                        		'';
                    force = true;
                };
            })
        ]
    );
}
