{
  config,
  lib,
  pkgs,
  ...
}:
with lib;
let
  cfg = config.services.rqbit;
in
{
  options.services.rqbit = {
    enable = mkEnableOption "rqbit BitTorrent client";

    package = mkOption {
      type = types.package;
      default = pkgs.rqbit;
      defaultText = literalExpression "pkgs.rqbit";
      description = "The rqbit package to use.";
    };

    dataDir = mkOption {
      type = types.path;
      default = "/var/lib/rqbit";
      description = "Directory to store downloaded torrents.";
    };

    # HTTP API Configuration
    httpApi = {
      listenAddress = mkOption {
        type = types.str;
        default = "127.0.0.1";
        description = "IP address to listen on for the web UI and API.";
      };

      listenPort = mkOption {
        type = types.port;
        default = 3030;
        description = "Port for the web UI and API.";
      };

      openFirewall = mkOption {
        type = types.bool;
        default = false;
        description = "Open the firewall for the web UI port.";
      };
    };

    # BitTorrent TCP Configuration
    tcp = {
      minPort = mkOption {
        type = types.port;
        default = 4240;
        description = "Minimum port for incoming BitTorrent connections.";
      };

      maxPort = mkOption {
        type = types.port;
        default = 4260;
        description = "Maximum port for incoming BitTorrent connections.";
      };

      disable = mkOption {
        type = types.bool;
        default = false;
        description = "Disable listening for incoming TCP connections.";
      };

      openFirewall = mkOption {
        type = types.bool;
        default = false;
        description = "Open firewall ports for incoming BitTorrent connections.";
      };
    };

    # DHT Configuration
    dht = {
      disable = mkOption {
        type = types.bool;
        default = false;
        description = "Disable DHT (Distributed Hash Table) for peer discovery.";
      };

      disablePersistence = mkOption {
        type = types.bool;
        default = false;
        description = "Disable DHT state persistence (useful for multiple instances).";
      };
    };

    # UPnP Configuration
    upnp = {
      disablePortForward = mkOption {
        type = types.bool;
        default = false;
        description = "Disable UPnP port forwarding.";
      };

      enableServer = mkOption {
        type = types.bool;
        default = false;
        description = "Enable UPnP Media Server to stream torrents.";
      };

      serverFriendlyName = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Friendly name for the UPnP server.";
        example = "rqbit Media Server";
      };
    };

    # Rate Limiting
    rateLimit = {
      download = mkOption {
        type = types.nullOr types.int;
        default = null;
        description = "Download rate limit in bytes per second.";
        example = 1048576; # 1 MB/s
      };

      upload = mkOption {
        type = types.nullOr types.int;
        default = null;
        description = "Upload rate limit in bytes per second.";
        example = 524288; # 512 KB/s
      };
    };

    # Logging Configuration
    logging = {
      level = mkOption {
        type = types.nullOr (
          types.enum [
            "trace"
            "debug"
            "info"
            "warn"
            "error"
          ]
        );
        default = null;
        description = "Console log level.";
      };

      file = mkOption {
        type = types.nullOr types.path;
        default = null;
        description = "Log file path (in addition to console logging).";
        example = "/var/log/rqbit/rqbit.log";
      };

      fileRustLog = mkOption {
        type = types.str;
        default = "librqbit=debug,info";
        description = "RUST_LOG value for the log file.";
      };
    };

    # Performance Configuration
    performance = {
      workerThreads = mkOption {
        type = types.nullOr types.ints.positive;
        default = null;
        description = "Number of worker threads for the executor.";
      };

      maxBlockingThreads = mkOption {
        type = types.ints.positive;
        default = 8;
        description = "Maximum blocking threads for disk I/O operations.";
      };

      singleThreadRuntime = mkOption {
        type = types.bool;
        default = false;
        description = "Use tokio's single-threaded runtime (for debugging).";
      };

      concurrentInitLimit = mkOption {
        type = types.ints.positive;
        default = 5;
        description = "Maximum number of torrents that can initialize simultaneously.";
      };
    };

    # Peer Configuration
    peer = {
      connectTimeout = mkOption {
        type = types.str;
        default = "2s";
        description = "Peer connection timeout.";
        example = "1.5s";
      };

      readWriteTimeout = mkOption {
        type = types.str;
        default = "10s";
        description = "Peer read/write timeout.";
        example = "5s";
      };
    };

    # Tracker Configuration
    tracker = {
      refreshInterval = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Force a specific tracker refresh interval.";
        example = "30s";
      };

      trackersFile = mkOption {
        type = types.nullOr types.path;
        default = null;
        description = "File with tracker URLs to use for all torrents.";
      };
    };

    # Advanced Options
    socksProxy = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "SOCKS5 proxy URL.";
      example = "socks5://user:pass@localhost:1080";
    };

    blocklistUrl = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "URL to download a P2P blocklist from.";
      example = "https://example.com/blocklist.txt";
    };

    umask = mkOption {
      type = types.nullOr types.str;
      default = null;
      description = "Set the process umask for file creation permissions.";
      example = "022";
    };

    # User/Group Configuration
    user = mkOption {
      type = types.str;
      default = "rqbit";
      description = "User account under which rqbit runs.";
    };

    group = mkOption {
      type = types.str;
      default = "rqbit";
      description = "Group under which rqbit runs.";
    };

    extraArgs = mkOption {
      type = types.listOf types.str;
      default = [ ];
      description = "Extra command-line arguments to pass to rqbit.";
      example = literalExpression ''[ "--experimental-mmap-storage" ]'';
    };
  };

  config = mkIf cfg.enable {
    systemd.services.rqbit = {
      description = "rqbit BitTorrent Client";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      preStart = mkIf (cfg.logging.file != null) ''
        mkdir -p $(dirname ${cfg.logging.file})
        chown ${cfg.user}:${cfg.group} $(dirname ${cfg.logging.file})
      '';

      serviceConfig = {
        Type = "simple";
        User = cfg.user;
        Group = cfg.group;
        Environment = [
          "XDG_CACHE_HOME=${cfg.dataDir}/.cache"
          "XDG_DATA_HOME=${cfg.dataDir}/.local/share"
        ];
        ExecStart =
          let
            args = [
              "${cfg.package}/bin/rqbit"
              "--http-api-listen-addr ${cfg.httpApi.listenAddress}:${toString cfg.httpApi.listenPort}"
            ]
            ++ optional (cfg.logging.level != null) "-v ${cfg.logging.level}"
            ++ optional (cfg.logging.file != null) "--log-file ${cfg.logging.file}"
            ++ optional (cfg.logging.file != null) "--log-file-rust-log ${cfg.logging.fileRustLog}"
            ++ optional (cfg.tracker.refreshInterval != null) "-i ${cfg.tracker.refreshInterval}"
            ++ optional cfg.performance.singleThreadRuntime "-s"
            ++ optional cfg.dht.disable "--disable-dht"
            ++ optional cfg.dht.disablePersistence "--disable-dht-persistence"
            ++ optional (cfg.peer.connectTimeout != "2s") "--peer-connect-timeout ${cfg.peer.connectTimeout}"
            ++ optional (
              cfg.peer.readWriteTimeout != "10s"
            ) "--peer-read-write-timeout ${cfg.peer.readWriteTimeout}"
            ++ optional (cfg.performance.workerThreads != null) "-t ${toString cfg.performance.workerThreads}"
            ++ optional cfg.tcp.disable "--disable-tcp-listen"
            ++ optional (cfg.tcp.minPort != 4240) "--tcp-min-port ${toString cfg.tcp.minPort}"
            ++ optional (cfg.tcp.maxPort != 4260) "--tcp-max-port ${toString cfg.tcp.maxPort}"
            ++ optional cfg.upnp.disablePortForward "--disable-upnp-port-forward"
            ++ optional cfg.upnp.enableServer "--enable-upnp-server"
            ++ optional (
              cfg.upnp.serverFriendlyName != null
            ) "--upnp-server-friendly-name '${cfg.upnp.serverFriendlyName}'"
            ++ optional (
              cfg.performance.maxBlockingThreads != 8
            ) "--max-blocking-threads ${toString cfg.performance.maxBlockingThreads}"
            ++ optional (cfg.socksProxy != null) "--socks-url ${cfg.socksProxy}"
            ++ optional (
              cfg.performance.concurrentInitLimit != 5
            ) "--concurrent-init-limit ${toString cfg.performance.concurrentInitLimit}"
            ++ optional (cfg.umask != null) "--umask ${cfg.umask}"
            ++ optional (
              cfg.rateLimit.download != null
            ) "--ratelimit-download ${toString cfg.rateLimit.download}"
            ++ optional (cfg.rateLimit.upload != null) "--ratelimit-upload ${toString cfg.rateLimit.upload}"
            ++ optional (cfg.blocklistUrl != null) "--blocklist-url ${cfg.blocklistUrl}"
            ++ optional (cfg.tracker.trackersFile != null) "--trackers-filename ${cfg.tracker.trackersFile}"
            ++ cfg.extraArgs
            ++ [
              "server"
              "start"
              cfg.dataDir
            ];
          in
          concatStringsSep " " args;
        Restart = "on-failure";
        StateDirectory = "rqbit";
        NoNewPrivileges = true;
        PrivateTmp = true;
        ProtectSystem = "strict";
        ReadWritePaths = [ cfg.dataDir ] ++ optional (cfg.logging.file != null) (dirOf cfg.logging.file);
      };
    };

    users.users = mkIf (cfg.user == "rqbit") {
      rqbit = {
        isSystemUser = true;
        group = cfg.group;
        description = "rqbit BitTorrent client user";
      };
    };

    users.groups = mkIf (cfg.group == "rqbit") {
      rqbit = { };
    };

    networking.firewall = mkIf (cfg.httpApi.openFirewall || cfg.tcp.openFirewall) {
      allowedTCPPorts = optional cfg.httpApi.openFirewall cfg.httpApi.listenPort;
      allowedTCPPortRanges = optional cfg.tcp.openFirewall {
        from = cfg.tcp.minPort;
        to = cfg.tcp.maxPort;
      };
    };
  };
}
