{
  config,
  lib,
  pkgs,
  ...
}:
let
  cfg = config.services.podman;

  podman-lib = import ./podman-lib.nix { inherit pkgs lib config; };
  activation = import ./activation.nix { inherit config podman-lib; };

  activationCleanupScript = activation.cleanup;

  # derivation to build a single Podman quadlet, outputting its systemd unit files
  buildPodmanQuadlet =
    quadlet:
    let
      quadletFile = pkgs.writeText "${quadlet.serviceName}.${quadlet.resourceType}" quadlet.source;
    in
    pkgs.stdenv.mkDerivation {
      name = "home-${quadlet.resourceType}-${quadlet.serviceName}";

      src = quadletFile;

      buildInputs = [ cfg.package ] ++ quadlet.dependencies;

      unpackPhase = ''
        mkdir -p $out/quadlets
        ln -s $src $out/quadlets/${quadlet.serviceName}.${quadlet.resourceType}
        ${lib.concatStringsSep "\n" (
          map (
            v:
            "echo 'linking ${v.quadletData.serviceName}.${v.quadletData.resourceType}'; ln -s ${v.out}/quadlets/${v.quadletData.serviceName}.${v.quadletData.resourceType} $out/quadlets"
          ) quadlet.dependencies
        )}
      '';

      installPhase = ''
        # Directory for systemd unit files
        mkdir -p $out/units

        # Generate systemd unit file/s from the quadlet file
        export QUADLET_UNIT_DIRS=$out/quadlets
        ${cfg.package}/lib/systemd/user-generators/podman-user-generator $out/units
      '';

      passthru = {
        outPath = lib.self.out;
        quadletData = quadlet;
      };
    };

  builtQuadlets = map buildPodmanQuadlet cfg.internal.quadletDefinitions;

  accumulateUnitFiles =
    prefix: path: quadlet:
    let
      entries = builtins.readDir path;
      processEntry =
        name: type:
        let
          newPath = "${path}/${name}";
          newPrefix = prefix + (if prefix == "" then "" else "/") + name;
        in
        if type == "directory" then
          accumulateUnitFiles newPrefix newPath quadlet
        else
          [
            {
              key = newPrefix;
              value = {
                path = newPath;
                parentQuadlet = quadlet;
              };
            }
          ];
    in
    lib.flatten (map (name: processEntry name (lib.getAttr name entries)) (lib.attrNames entries));

  allUnitFiles = lib.concatMap (
    builtQuadlet: accumulateUnitFiles "" "${builtQuadlet.outPath}/units" builtQuadlet.quadletData
  ) builtQuadlets;

  # we're doing this because the home-manager recursive file linking implementation can't
  # merge from multiple sources. so we link each file explicitly, which is fine for all unique files
  generateSystemdFileLinks =
    files:
    lib.listToAttrs (
      map (unitFile: {
        name = "${config.xdg.configHome}/systemd/user/${unitFile.key}";
        value = {
          source = unitFile.value.path;
        };
      }) files
    );

in
{
  imports = [ ./options.nix ];

  config = lib.mkIf cfg.enable {
    home.file = generateSystemdFileLinks allUnitFiles;

    # if the length of builtQuadlets is 0, then we don't need register the activation script
    home.activation.podmanQuadletCleanup = lib.mkIf (lib.length builtQuadlets >= 1) (
      lib.hm.dag.entryAfter [ "reloadSystemd" ] activationCleanupScript
    );

    services.podman.internal.builtQuadlets = lib.listToAttrs (
      map (pkg: {
        name =
          (lib.removePrefix "podman-" pkg.passthru.quadletData.serviceName)
          + "."
          + pkg.passthru.quadletData.resourceType;
        value = pkg;
      }) builtQuadlets
    );
  };
}
