{lib, config, ...}:
let
  cfg = config.helixApp;

  # helix theming docs: https://docs.helix-editor.com/themes.html
  # Check current stylix theme: ~/.config/helix/themes/stylix.toml
  # And computed minimal: ~/.config/helix/themes/minimal.toml

  # Minimal syntax highlighting theme using base16 colors
  # Philosophy: "If everything is highlighted, nothing is"
  # Highlight comments, keywords, strings, and constants, all else uses style, not color
  minimalTheme = {
    # Inherit Stylix's base theme (UI, palette, etc.)
    inherits = "stylix";

    # Comments
    "comment" = { fg = "base0A"; modifiers = ["italic"]; };

    # Keywords
    "keyword" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.control" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.directive" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.function" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.operator" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.return" = { fg = "base0E"; modifiers = ["italic"]; };
    "keyword.storage" = { fg = "base0E"; modifiers = ["italic"]; };

    # Strings
    "string" = "base0B";
    "string.regexp" = "base0B";
    "string.special" = "base0B";

    # Constants/Numbers
    "constant" = "base08";
    "constant.numeric" = "base08";
    "constant.builtin" = "base08";
    "constant.character" = "base08";
    "constant.character.escape" = "base08";

    # === SUBTLE HIGHLIGHTING ===

    # Types
    "type" = { fg = "base0F"; modifiers = ["bold"]; };
    "type.builtin" = { fg = "base0F"; modifiers = ["bold"]; };
    "type.enum" = { fg = "base0F"; modifiers = ["bold"]; };
    "type.enum.variant" = { fg = "base0F"; modifiers = ["bold"]; };

    # Definitions - bold+italic, same color as text (landmarks)
    "function.definition" = { fg = "base07"; modifiers = ["bold" "italic"]; };
    "type.definition" = { fg = "base07"; modifiers = ["bold" "italic"]; };

    # === PLAIN TEXT (majority of code) ===

    # Functions - plain text
    "function" = "base07";
    "function.builtin" = "base07";
    "function.method" = "base07";
    "function.macro" = "base07";

    # Variables - plain text
    "variable" = "base05";
    "variable.builtin" = "base07";
    "variable.parameter" = "base05";
    "variable.other" = "base05";
    "variable.other.member" = "base05";

    # Other constructs - plain text
    "constructor" = "base05";
    "attribute" = "base05";
    "label" = "base05";
    "namespace" = "base05";
    "tag" = "base05";
    "special" = "base05";

    # Punctuation - plain text, dim
    "punctuation" = { fg = "base05"; modifiers = ["dim"]; };
    "punctuation.bracket" = { fg = "base05"; modifiers = ["dim"]; };
    "punctuation.delimiter" = { fg = "base05"; modifiers = ["dim"]; };
    "punctuation.special" = { fg = "base05"; modifiers = ["dim"]; };
    "operator" = { fg = "base05"; modifiers = ["dim"]; };

    # === MARKUP (documents) ===
    "markup.heading" = { fg = "base0E"; modifiers = ["bold"]; };
    "markup.heading.1" = { fg = "base0E"; modifiers = ["bold"]; underline.style = "double_line";};
    "markup.heading.2" = { fg = "base0B"; modifiers = ["bold"]; underline.style = "line";};
    "markup.heading.3" = { fg = "base08"; modifiers = ["bold"]; underline.style = "line";};
    "markup.heading.4" = { fg = "base0C"; modifiers = ["bold"]; };
    "markup.heading.5" = { fg = "base0D"; modifiers = ["bold"]; };
    "markup.heading.6" = { fg = "base0F"; modifiers = ["bold"]; };
    "markup.list" = "base0E";
    "markup.list.checked" = { modifiers = ["crossed_out"]; };
    "markup.bold" = { modifiers = ["bold"]; };
    "markup.italic" = { modifiers = ["italic"]; };
    "markup.strikethrough" = { modifiers = ["crossed_out"]; };
    "markup.link.url" = { fg = "base09"; underline.style = "line"; };
    "markup.link.text" = "base0E";
    "markup.quote" = "base0B";
    "markup.raw" = "base06";
    # "markup.raw.inline" = "base06";
    # "markup.raw.block" = { fg = "base06"; bg = "";};

    # === UI Tweaks ===
    "ui.text.directory" = { fg = "base06"; modifiers = ["italic"]; }; # directory in popups
    "ui.text.focus" = { fg = "base07"; modifiers = ["bold"]; }; # selected line in pickers
  };
in
{
  options.helixApp = {
    enable = lib.mkEnableOption "enable helix editor";

    themeOverrides = lib.mkOption {
      type = lib.types.attrsOf lib.types.anything;
      default = {};
      description = ''
        Override helix theme scopes. These are merged with the minimal base theme.
        Uses base16 color names (base00-base0F) for Stylix integration.

        Example: Make types plain text instead of subtle:
          themeOverrides = { "type" = "base05"; };
      '';
      example = {
        "type" = "base05";
        "comment" = { fg = "base03"; modifiers = ["italic"]; };
      };
    };
  };

  config = lib.mkIf cfg.enable {
    # Let Stylix generate its base theme (for UI elements, palette)
    stylix.targets.helix.enable = true;

    programs.helix = {
      enable = true;

      # Use our minimal theme instead of Stylix's default
      settings.theme = lib.mkForce "minimal";

      # Define minimal theme that inherits Stylix's palette but overrides syntax highlighting
      themes.minimal = minimalTheme // cfg.themeOverrides;

      settings = {
        keys.normal = {
          # Navigation (Colemak-DH)
          n = "move_char_left";
          i = "move_visual_line_down";
          e = "move_visual_line_up";
          o = "move_char_right";
          "S-tab" = "jump_backward";
          I = [ "page_cursor_half_down" "align_view_center" ];
          E = [ "page_cursor_half_up" "align_view_center" ];

          # Modes
          h = "insert_mode";
          H = "insert_at_line_start";
          l = "open_below";
          L = "open_above";

          # Search
          k = "search_next";
          K = "search_prev";

          # Selection
          j = "join_selections";
          J = "yank_joined";
          C-s = "split_selection_on_newline";
          C-minus = "merge_selections";
          C-_ = "merge_consecutive_selections";
          "C-;" = "flip_selections";
          "C-:" = "ensure_selections_forward";
          "C-," = "remove_primary_selection";
          C-c = "change_selection_noyank";
          C-d = "delete_selection_noyank";
          "C-(" = "rotate_selection_contents_backward";
          "C-)" = "rotate_selection_contents_forward";
          C-x = "shrink_to_line_bounds";
          C-J = "join_selections_space";
          C-K = "remove_selections";
          C-e = "expand_selection";
          C-i = "shrink_selection";
          C-n = "select_prev_sibling";
          C-o = "select_next_sibling";

          # Misc
          "C-/" = "toggle_comments";
          "@" = ":append-output git config get user.email";

          space = {
            B = ":sh git log -n 5 --format='format:%%h (%%an: %%ar) %%s' --no-patch -L%{cursor_line},+1:%{buffer_name}";
            x = ":buffer-close";
            X = ":write-quit-all";
            o = ":config-open";
            h = "hover";
            k = "select_references_to_symbol_under_cursor";
            # Copy a permalink to the current line in the remote git viewer
            # (GitHub/GitLab use /blob/<sha>/, Gitea/Codeberg use /src/commit/<sha>/).
            "@" = ":sh f=%{buffer_name}; l=%{cursor_line}; d=$(dirname \"$f\"); url=$(git -C \"$d\" config --get remote.origin.url) || { echo \"not a git repo or no origin remote\" >&2; exit 1; }; [ -n \"$url\" ] || { echo \"no origin remote\" >&2; exit 1; }; sha=$(git -C \"$d\" rev-parse HEAD) || exit 1; rel=$(git -C \"$d\" ls-files --full-name --error-unmatch -- \"$f\" 2>&1) || { echo \"file not tracked: $rel\" >&2; exit 1; }; command -v wl-copy >/dev/null || { echo \"wl-copy not installed\" >&2; exit 1; }; url=\${url%%.git}; case \"$url\" in git@*) host=\${url#git@}; host=\${host%%:*}; path=\${url#*:}; url=\"https://$host/$path\" ;; esac; case \"$url\" in *github.com*|*gitlab.com*) link=\"$url/blob/$sha/$rel#L$l\" ;; *) link=\"$url/src/commit/$sha/$rel#L$l\" ;; esac; printf '%%s' \"$link\" | wl-copy";
          };

          g = {
            "/" = "goto_next_buffer";
            h = "goto_previous_buffer";
            n = [ "collapse_selection" "extend_to_line_start" ];
            o = [ "collapse_selection" "extend_to_line_end" ];
            e = "move_line_up";
            i = "goto_implementation";
            l = "goto_last_line";
            p = "no_op";
            k = "no_op";
            j = "no_op";
          };

          m.m = [ "select_mode" "match_brackets" "normal_mode" ];

          "C-w" = {
            h = "hsplit";
            C-h = "hsplit";
            n = "jump_view_left";
            C-n = "jump_view_left";
            i = "jump_view_down";
            I = "swap_view_down";
            C-i = "jump_view_down";
            e = "jump_view_up";
            E = "swap_view_up";
            C-e = "jump_view_up";
            o = "jump_view_right";
            O = "swap_view_right";
            C-o = "jump_view_right";
            # Remove old
            s = "no_op";
            C-s = "no_op";
            H = "no_op";
            j = "no_op";
            J = "no_op";
            C-j = "no_op";
            k = "no_op";
            K = "no_op";
            C-k = "no_op";
            l = "no_op";
            L = "no_op";
            C-l = "no_op";
          };
        };

        keys.select = {
          n = "extend_char_left";
          i = "extend_line_down";
          e = "extend_line_up";
          o = "extend_char_right";
          I = [ "page_cursor_half_down" "align_view_center" ];
          E = [ "page_cursor_half_up" "align_view_center" ];

          g = {
            "/" = "goto_next_buffer";
            h = "goto_previous_buffer";
            n = "goto_line_start";
            o = "goto_line_end";
            e = "move_line_up";
            i = "move_line_down";
            l = "goto_last_line";
            p = "no_op";
            k = "no_op";
            j = "no_op";
          };
        };

        editor = {
          auto-format = true;
          auto-save = true;
          bufferline = "always";
          color-modes = true;
          completion-timeout = 5;
          cursorcolumn = true;
          cursorline = true;
          indent-heuristic = "tree-sitter";
          line-number = "relative";
          rulers = [ 120 ];
          text-width = 120;
          end-of-line-diagnostics = "hint";

          cursor-shape = {
            insert = "bar";
            normal = "block";
            select = "underline";
          };

          file-picker.hidden = false;

          indent-guides.render = true;

          inline-diagnostics = {
            cursor-line = "warning";
            other-lines = "disable";
            prefix-len = 5;
            max-diagnostics = 1;
            max-wrap = 30;
          };

          lsp = {
            display-messages = true;
            display-inlay-hints = true;
          };

          soft-wrap = {
            enable = true;
            max-wrap = 30;
          };

          statusline = {
            left = [ "mode" "file-modification-indicator" "spinner" "version-control" ];
            center = [ "file-name" ];
            right = [ "diagnostics" "selections" "register" "position" "file-encoding" ];
            mode.normal = "Normal";
            mode.insert = "Insert";
            mode.select = "Select";
          };

          whitespace.render = {
            space = "all";
            tab = "all";
            tabpad = "all";
            newline = "none";
            nbsp = "none";
          };

          whitespace.characters = {
            space = " ";
            tab = "⇀";
            tabpad = " ";
          };
        };
      };

      languages = {
        language = [
          {
            name = "go";
            debugger = {
              name = "go";
              transport = "tcp";
              command = "dlv";
              args = [ "connect" ];
              port-arg = "127.0.0.1:2345";
              templates = [{
                name = "connect";
                request = "launch";
                completion = [];
                args = {};
              }];
            };
          }
          {
            name = "markdown";
            language-servers = [ "ltex-ls" "marksman" ];
          }
          {
            name = "dart";
            formatter = { command = "dart"; args = [ "format" "-l" "120" ]; };
            language-servers = [ "dart" ];
          }
          {
            name = "nix";
            language-servers = [ "nil" ];
          }
          {
            name = "zig";
            language-servers = [ "zls" ];
            debugger = {
              name = "codelldb-dap";
              transport = "tcp";
              command = "codelldb";
              args = [];
              port-arg = "--port {}";
              templates = [
                {
                  name = "launch";
                  request = "launch";
                  completion = [{ name = "binary"; completion = "filename"; }];
                  args = { console = "internalConsole"; program = "{0}"; };
                }
                {
                  name = "attach";
                  request = "attach";
                  completion = [ "pid" ];
                  args = { console = "internalConsole"; pid = "{0}"; };
                }
                {
                  name = "gdbserver attach";
                  request = "attach";
                  completion = [
                    { name = "lldb connect url"; default = "connect://localhost:3333"; }
                    { name = "file"; completion = "filename"; }
                    "pid"
                  ];
                  args = {
                    console = "internalConsole";
                    attachCommands = [
                      "platform select remote-gdb-server"
                      "platform connect {0}"
                      "file {1}"
                      "attach {2}"
                    ];
                  };
                }
              ];
            };
          }
          {
            name = "cyano";
            scope = "source.cyo";
            file-types = [ "cyo" ];
            language-servers = [ "ltex-ls" ];
          }
        ];

        language-server.ltex-ls = {
          command = "ltex-ls";
        };
      };
    };
  };
}
