# TODO maybe use `nix eval --raw .#odo.iso.outPath`

#
# Install on a new machine:
#
# Set
#   me.disko.enable = true;
#   me.disko.offline.enable = true;
#
# Run
#   doas disko --mode destroy,format,mount hosts/recovery/disk-config.nix
#   doas nixos-install --substituters "http://10.0.2.2:8080?trusted=1 https://cache.nixos.org/" --flake ".#recovery"

{
  description = "My system configuration";

  inputs = {
    impermanence = {
      url = "github:nix-community/impermanence";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    lanzaboote = {
      url = "github:nix-community/lanzaboote/v0.4.2";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    disko = {
      url = "github:nix-community/disko";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs =
    {
      self,
      nixpkgs,
      disko,
      impermanence,
      lanzaboote,
      ...
    }:
    let
      forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
      nodes = {
        odo = {
          system = "x86_64-linux";
        };
        odowork = {
          system = "x86_64-linux";
        };
        quark = {
          system = "x86_64-linux";
        };
        recovery = {
          system = "x86_64-linux";
        };
        i_only_boot_zfs = {
          system = "x86_64-linux";
        };
        hydra = {
          system = "x86_64-linux";
        };
        family_disks = {
          system = "x86_64-linux";
        };
      };
      nixosConfigs = builtins.mapAttrs (
        hostname: nodeConfig: format:
        nixpkgs.lib.nixosSystem {
          specialArgs = {
            inherit self;

            this_nixos_config = self.nixosConfigurations."${hostname}";

            all_nixos_configs = self.nixosConfigurations;
          };
          modules = [
            impermanence.nixosModules.impermanence
            lanzaboote.nixosModules.lanzaboote
            disko.nixosModules.disko
            ./configuration.nix
            (./. + "/hosts/${hostname}")
            (./. + "/formats/${format}.nix")
            {
              config = {
                nixpkgs.hostPlatform.system = nodeConfig.system;
                nixpkgs.overlays = [
                  (final: prev: {
                    # stable = nixpkgs-stable.legacyPackages."${prev.stdenv.hostPlatform.system}";
                    unoptimized = import nixpkgs {
                      system = prev.stdenv.hostPlatform.system;
                      hostPlatform.gcc.arch = "default";
                      hostPlatform.gcc.tune = "default";
                    };
                  })
                ];
              };
            }
          ];
        }
      ) nodes;
      installerConfig =
        hostname: nodeConfig:
        nixpkgs.lib.nixosSystem {
          specialArgs = {
            targetSystem = self.nixosConfigurations."${hostname}";
          };
          modules = [
            ./formats/installer.nix
            ({ nixpkgs.hostPlatform.system = nodeConfig.system; })
          ];
        };
    in
    {
      nixosConfigurations = (builtins.mapAttrs (name: value: value "toplevel") nixosConfigs);
    }
    // {
      packages = (
        forAllSystems (
          system:
          (builtins.mapAttrs (hostname: nodeConfig: {
            iso = (nixosConfigs."${hostname}" "iso").config.system.build.isoImage;
            vm_iso = (nixosConfigs."${hostname}" "vm_iso").config.system.build.isoImage;
            sd = (nixosConfigs."${hostname}" "sd").config.system.build.sdImage;
            installer = (installerConfig hostname nodes."${hostname}").config.system.build.isoImage;
          }) (nixpkgs.lib.attrsets.filterAttrs (hostname: nodeConfig: nodeConfig.system == system) nodes))
        )
      );
    };
}
