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

with lib;
let
  cfg = config.my.programs.python;

  pythonVersions = map (version: "3${toString version}") (range 8 11);
  enabledVersions = filterAttrs (name: value: value.enable) cfg.versions;

  pythonPackages = version: attrNames pkgs."python${version}Packages";

  commonPackages =
    let
      packageLists = map pythonPackages (attrNames enabledVersions);
    in
    foldl' intersectLists (head packageLists) (tail packageLists);

  versionOpts = version: {
    enable = mkEnableOption (toString version);
    pythonPackages = mkOption {
      default = [ ];
      type = with types; listOf (enum (pythonPackages version));
    };
  };
in
{
  options.my.programs.python = {
    versions = genAttrs pythonVersions versionOpts;
    defaultPackages = mkOption {
      default = [ ];
      type = with types; listOf (enum commonPackages);
    };
    extraPackages = mkOption {
      default = with pkgs; [
        poetry
        ruff
        python310Packages.python-lsp-server
      ];
      type = with types; listOf package;
    };
  };

  config = {
    users.users.moritz.packages =
      (
        let
          mkPython = version:
            let
              package = pkgs."python${version}";
              finalPythonPackages = cfg.versions.${version}.pythonPackages ++ cfg.defaultPackages;
              getPythonPackages = ps: map (flip getAttr ps) finalPythonPackages;
            in
            package.withPackages getPythonPackages;
        in
        map mkPython (attrNames enabledVersions)
      ) ++ cfg.extraPackages;
  };
}
