{ config, lib, pkgs, ... }: let
  cfg = config.security.pam.yubico;

in {
  options.security.pam.yubico = {
    logoutOnRemove = lib.mkEnableOption "Logout on Yubikey remove";
    asClient = lib.mkEnableOption "Use Yubikey as client";
    clients = lib.mkOption {
      type = with lib.types; attrsOf (listOf str);
      example = { myUser = [ "myYubikeyTokenID" ]; };
      default = {};
      description = "The users that are allowed to use the Yubikey";
    };

    product_id = lib.mkOption {
      type = lib.types.str;
      default = "1050/407/543";
      description = "The product id of the Yubikey";
    };
  };

  config = lib.mkIf cfg.enable {
    systemd.tmpfiles.rules = let
      keysFiles = builtins.mapAttrs (n: v: pkgs.writeText "authorized_yubikeys_${n}" ''
        ${lib.concatStringsSep ":" ([ n ] ++ v)}
      '') cfg.clients;
    in if cfg.asClient then
      (builtins.concatMap (n: [
        "d /home/${n}/.yubico 0655 ${n} users -"
        "L+ /home/${n}/.yubico/authorized_yubikeys 0644 ${n} users - ${keysFiles.${n}}"
        "Z /home/${n}/.yubico - root root"
      ]) (builtins.attrNames cfg.clients))
    else
      [ "d /var/yubico 0700 root root -" ];

    services.udev.extraRules = lib.mkIf (cfg.logoutOnRemove && !cfg.asClient) ''
        SUBSYSTEM=="usb", ACTION=="remove", ENV{PRODUCT}=="${cfg.product_id}", RUN+="${pkgs.systemd}/bin/loginctl lock-sessions"
    '';

    security.pam = {
      services.hyprlock.yubicoAuth = lib.mkIf config.programs.hyprlock.enable false;
      yubico = {
        id = "106508";
        mode = if cfg.asClient then "client" else "challenge-response";
        control = "required";
        challengeResponsePath = lib.mkIf (!cfg.asClient) "/var/yubico";
      };
    };
  };
}