# This shouldn't be a part of the foodogsquared's library set. These are simply
# environment builders used to build consistent environments throughout flake-
# and non-flake-based Nix environments. Much of the things here are unofficial
# and basically redoing what the upstream projects are doing so maintenance is
# pretty much higher here.
#
# Anyways, all we're doing here is to see how much of a pain to use those Nix
# projects especially those that are entirely relying on flakes.
#
# Despite named similarly to npins `sources` convention, it should also work
# for flake-based setups as long as the inputs attrset from the flake output
# function is the one that is passed.
{ lib, foodogsquaredLib, sources }:

let
  # A set of nixos-generators modules including our custom ones.
  nixosGeneratorModules =
    let
      officialFormats = builtins.readDir "${sources.nixos-generators}/formats";
      unofficialFormats = builtins.readDir ../modules/nixos-generators;
      formats = officialFormats // unofficialFormats;
    in
    lib.mapAttrs' (n: _: lib.nameValuePair (lib.removeSuffix ".nix" n) {
      imports = [
        "${sources.nixos-generators}/format-module.nix"
        (
          if (lib.hasAttr n officialFormats)
          then "${sources.nixos-generators}/formats/${n}"
          else "${../modules/nixos-generators}/${n}"
        )
      ];
    }) formats;
in
rec {
  mkNixosSystem = {
    pkgs,
    lib ? pkgs.lib,
    system,
    extraModules ? [ ],
    specialArgs ? { },
  }:
    let
      nixosModules = ../modules/nixos;

      # Evaluating the system ourselves (which is trivial) instead of relying
      # on nixpkgs.lib.nixosSystem flake output.
      nixosSystem = args: import "${pkgs.path}/nixos/lib/eval-config.nix" args;
    in
    (lib.makeOverridable nixosSystem) {
      inherit pkgs;
      specialArgs = specialArgs // {
        foodogsquaredUtils = import ./utils/nixos.nix { inherit lib; };
        foodogsquaredModulesPath = builtins.toString nixosModules;
      };
      modules = extraModules ++ [
        nixosModules
        ../modules/nixos/_private
        ({ lib, ... }: {
          nixpkgs.hostPlatform = lib.mkForce system;
        })
      ];

      # Since we're setting it through nixpkgs.hostPlatform, we'll have to pass
      # this as null.
      system = null;
    };

  # A very very thin wrapper around `mkNixosSystem` to build with the given format.
  mkNixosImage = {
    pkgs,
    system,
    lib ? pkgs.lib,
    extraModules ? [ ],
    specialArgs ? { },
    format ? "iso",
  }:
    let
      extraModules' = extraModules ++ [ nixosGeneratorModules.${format} ];
      nixosSystem = mkNixosSystem {
        inherit pkgs lib system specialArgs;
        extraModules = extraModules';
      };
    in
    nixosSystem.config.system.build.${nixosSystem.config.formatAttr};

  mkHome = {
    pkgs,
    homeManagerSrc,
    lib ? pkgs.lib,
    modules ? [ ],
    specialArgs ? { },
  }:
    let
      homeModules = ../modules/home-manager;
    in
    import "${homeManagerSrc}/modules" {
      inherit pkgs lib;
      check = true;
      extraSpecialArgs = specialArgs // {
        foodogsquaredModulesPath = builtins.toString homeModules;
      };
      configuration = { lib, ... }: {
        imports = modules ++ [
          homeModules
          ../modules/home-manager/_private
        ];

        config = {
          programs.home-manager.path = homeManagerSrc;
          inherit (pkgs) overlays;
          nixpkgs.config = lib.mkDefault pkgs.config;
        };
      };
    };

  mkWrapper = {
    pkgs,
    lib ? pkgs.lib,
    wrapperManagerSrc,
    modules ? [ ],
    specialArgs ? { },
  }:
    let
      wrapperManagerModules = ../modules/wrapper-manager;
      wrapperManager = import wrapperManagerSrc { };
    in
      wrapperManager.lib.build {
        inherit pkgs lib;
        specialArgs = specialArgs // {
          foodogsquaredModulesPath = builtins.toString wrapperManagerModules;
        };
        modules = modules ++ [
          wrapperManagerModules
          ../modules/wrapper-manager/_private
        ];
      };
}