# Build ISO image
#   nix build --extra-experimental-features nix-command --extra-experimental-features flakes .#iso.odo
#   output: result/iso/nixos.iso

# Run the ISO image
#   doas "$(nix-build '<nixpkgs>' --no-out-link -A 'qemu')/bin/qemu-system-x86_64" \
#        -accel kvm \
#        -cpu host \
#        -smp cores=8 \
#        -m 32768 \
#        -drive "file=$(nix-build '<nixpkgs>' --no-out-link -A 'OVMF.fd')/FV/OVMF.fd,if=pflash,format=raw,readonly=on" \
#        -drive if=pflash,format=raw,file="/tmp/OVMF_VARS.fd" \
#        -nic user,hostfwd=tcp::60022-:22 \
#        -boot order=d \
#        -cdrom "$(readlink -f ./result/iso/nixos*.iso)" \
#        -display vnc=127.0.0.1:0
#
# doas cp "$(nix-build '<nixpkgs>' --no-out-link -A 'OVMF.fd')/FV/OVMF_VARS.fd" /tmp/OVMF_VARS.fd
# doas "$(nix-build '<nixpkgs>' --no-out-link -A 'qemu')/bin/qemu-system-x86_64" -accel kvm -cpu host -smp cores=8 -m 32768 -drive "file=$(nix-build '<nixpkgs>' --no-out-link -A 'OVMF.fd')/FV/OVMF.fd,if=pflash,format=raw,readonly=on" -drive if=pflash,format=raw,file="/tmp/OVMF_VARS.fd" -nic user,hostfwd=tcp::60022-:22 -boot order=d -cdrom /persist/machine_setup/nix/configuration/result/iso/nixos*.iso -display vnc=127.0.0.1:0

# Get a repl for this flake
#   nix repl --expr "builtins.getFlake \"$PWD\""

# TODO maybe use `nix eval --raw .#iso.odo.outPath`
# iso.odo.isoName == "nixos.iso"
# full path = <outPath> / iso / <isoName>

#
# Install on a new machine:
#
#
# doas nix --substituters "http://10.0.2.2:8080?trusted=1 https://cache.nixos.org/" --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount hosts/odo/disk-config.nix

# nix flake update zsh-histdb --flake .
# nix flake update ansible-sshjail --flake .
# for f in /persist/manual/manual_add_to_store/*; do nix-store --add-fixed sha256 "$f"; done
# nixos-install --substituters "http://10.0.2.2:8080?trusted=1 https://cache.nixos.org/" --flake ".#vm_ionlybootzfs"
#

{
  description = "My system configuration";

  inputs = {
    impermanence.url = "github:nix-community/impermanence";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nixpkgs-b93b4e9b5.url = "github:NixOS/nixpkgs/b93b4e9b527904aadf52dba6ca35efde2067cbd4";
    nixpkgs-unoptimized.url = "github:NixOS/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
    lanzaboote = {
      url = "github:nix-community/lanzaboote/v0.4.2";

      # Optional but recommended to limit the size of your system closure.
      inputs.nixpkgs.follows = "nixpkgs";
    };
    zsh-histdb = {
      url = "path:flakes/zsh-histdb";

      # Optional but recommended to limit the size of your system closure.
      inputs.nixpkgs.follows = "nixpkgs";
    };
    ansible-sshjail = {
      url = "path:flakes/ansible-sshjail";

      # Optional but recommended to limit the size of your system closure.
      inputs.nixpkgs.follows = "nixpkgs";
    };
    disko = {
      url = "github:nix-community/disko";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs =
    {
      self,
      nixpkgs,
      nixpkgs-unoptimized,
      nixpkgs-b93b4e9b5,
      impermanence,
      home-manager,
      lanzaboote,
      zsh-histdb,
      ansible-sshjail,
      ...
    }@inputs:
    let
      base_x86_64_linux = rec {
        system = "x86_64-linux";
        specialArgs = {
          pkgs-b93b4e9b5 = import nixpkgs-b93b4e9b5 {
            inherit system;
          };
          pkgs-unoptimized = import nixpkgs-unoptimized {
            inherit system;
            hostPlatform.gcc.arch = "default";
            hostPlatform.gcc.tune = "default";
          };
        };
        modules = [
          impermanence.nixosModules.impermanence
          home-manager.nixosModules.home-manager
          lanzaboote.nixosModules.lanzaboote
          inputs.disko.nixosModules.disko
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
          }
          {
            nixpkgs.overlays = [
              zsh-histdb.overlays.default
              ansible-sshjail.overlays.default
            ];
          }
          ./configuration.nix
        ];
      };
      systems =
        let
          additional_iso_modules = [
            (nixpkgs + "/nixos/modules/installer/cd-dvd/iso-image.nix")
            # TODO: Figure out how to do image based appliances
            # (nixpkgs + "/nixos/modules/profiles/image-based-appliance.nix")
            {
              isoImage.makeEfiBootable = true;
              isoImage.makeUsbBootable = true;
              me.buildingIso = true;
              me.optimizations.enable = nixpkgs.lib.mkForce false;
            }
            {
              # These are big space hogs. The chance that I need them on an ISO is slim.
              me.steam.enable = nixpkgs.lib.mkForce false;
              me.pcsx2.enable = nixpkgs.lib.mkForce false;
            }
          ];
          additional_vm_modules = [
            (nixpkgs + "/nixos/modules/profiles/qemu-guest.nix")
            {
              networking.dhcpcd.enable = true;
              networking.useDHCP = true;
              me.optimizations.enable = nixpkgs.lib.mkForce false;
            }
            {
              # I don't need games on a virtual machine.
              me.steam.enable = nixpkgs.lib.mkForce false;
              me.pcsx2.enable = nixpkgs.lib.mkForce false;
              me.sm64ex.enable = nixpkgs.lib.mkForce false;
              me.shipwright.enable = nixpkgs.lib.mkForce false;
              me.ship2harkinian.enable = nixpkgs.lib.mkForce false;
            }
          ];
        in
        {
          odo = rec {
            main = base_x86_64_linux // {
              modules = base_x86_64_linux.modules ++ [
                ./hosts/odo
              ];
            };
            iso = main // {
              modules = main.modules ++ additional_iso_modules;
            };
            vm = main // {
              modules = main.modules ++ additional_vm_modules;
            };
            vm_iso = main // {
              modules = main.modules ++ additional_vm_modules ++ additional_iso_modules;
            };
          };
          quark = rec {
            main = base_x86_64_linux // {
              modules = base_x86_64_linux.modules ++ [
                ./hosts/quark
              ];
            };
            iso = main // {
              modules = main.modules ++ additional_iso_modules;
            };
            vm = main // {
              modules = main.modules ++ additional_vm_modules;
            };
            vm_iso = main // {
              modules = main.modules ++ additional_vm_modules ++ additional_iso_modules;
            };
          };
          neelix = rec {
            main = base_x86_64_linux // {
              modules = base_x86_64_linux.modules ++ [
                ./hosts/neelix
              ];
            };
            iso = main // {
              modules = main.modules ++ additional_iso_modules;
            };
            vm = main // {
              modules = main.modules ++ additional_vm_modules;
            };
            vm_iso = main // {
              modules = main.modules ++ additional_vm_modules ++ additional_iso_modules;
            };
          };
          hydra =
            let
              additional_iso_modules = additional_iso_modules ++ [
                {
                  me.optimizations.enable = true;
                }
              ];
            in
            rec {
              main = base_x86_64_linux // {
                modules = base_x86_64_linux.modules ++ [
                  ./hosts/hydra
                ];
              };
              iso = main // {
                modules = main.modules ++ additional_iso_modules;
              };
              vm = main // {
                modules = main.modules ++ additional_vm_modules;
              };
              vm_iso = main // {
                modules = main.modules ++ additional_vm_modules ++ additional_iso_modules;
              };
            };
          ionlybootzfs = rec {
            main = base_x86_64_linux // {
              modules = base_x86_64_linux.modules ++ [
                ./hosts/ionlybootzfs
              ];
            };
            iso = main // {
              modules = main.modules ++ additional_iso_modules;
            };
            vm = main // {
              modules = main.modules ++ additional_vm_modules;
            };
            vm_iso = main // {
              modules = main.modules ++ additional_vm_modules ++ additional_iso_modules;
            };
          };

        };
    in
    {
      nixosConfigurations.odo = nixpkgs.lib.nixosSystem systems.odo.main;
      iso.odo = (nixpkgs.lib.nixosSystem systems.odo.iso).config.system.build.isoImage;
      nixosConfigurations.vm_odo = nixpkgs.lib.nixosSystem systems.odo.vm;
      vm_iso.odo = (nixpkgs.lib.nixosSystem systems.odo.vm_iso).config.system.build.isoImage;

      nixosConfigurations.quark = nixpkgs.lib.nixosSystem systems.quark.main;
      iso.quark = (nixpkgs.lib.nixosSystem systems.quark.iso).config.system.build.isoImage;
      nixosConfigurations.vm_quark = nixpkgs.lib.nixosSystem systems.quark.vm;
      vm_iso.quark = (nixpkgs.lib.nixosSystem systems.quark.vm_iso).config.system.build.isoImage;

      nixosConfigurations.neelix = nixpkgs.lib.nixosSystem systems.neelix.main;
      iso.neelix = (nixpkgs.lib.nixosSystem systems.neelix.iso).config.system.build.isoImage;
      nixosConfigurations.vm_neelix = nixpkgs.lib.nixosSystem systems.neelix.vm;
      vm_iso.neelix = (nixpkgs.lib.nixosSystem systems.neelix.vm_iso).config.system.build.isoImage;

      nixosConfigurations.hydra = nixpkgs.lib.nixosSystem systems.hydra.main;
      iso.hydra = (nixpkgs.lib.nixosSystem systems.hydra.iso).config.system.build.isoImage;
      nixosConfigurations.vm_hydra = nixpkgs.lib.nixosSystem systems.hydra.vm;
      vm_iso.hydra = (nixpkgs.lib.nixosSystem systems.hydra.vm_iso).config.system.build.isoImage;

      nixosConfigurations.ionlybootzfs = nixpkgs.lib.nixosSystem systems.ionlybootzfs.main;
      iso.ionlybootzfs = (nixpkgs.lib.nixosSystem systems.ionlybootzfs.iso).config.system.build.isoImage;
      nixosConfigurations.vm_ionlybootzfs = nixpkgs.lib.nixosSystem systems.ionlybootzfs.vm;
      vm_iso.ionlybootzfs =
        (nixpkgs.lib.nixosSystem systems.ionlybootzfs.vm_iso).config.system.build.isoImage;
    };
}