{
  description = "A very basic flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
    # Separate nixpkgs for qt5webengine-dependent packages (jellyfin-media-player, etc.)
    # Updates on separate Renovate schedule to avoid massive qt rebuilds
    nixpkgs-qt.url = "github:nixos/nixpkgs/nixos-25.11";

    nix-darwin = {
      url = "github:nix-darwin/nix-darwin/nix-darwin-25.11";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    home-manager = {
      url = "github:nix-community/home-manager/release-25.11";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    home-manager-unstable = {
      url = "github:nix-community/home-manager/master";
      inputs.nixpkgs.follows = "nixpkgs-unstable";
    };

    plasma-manager = {
      url = "github:nix-community/plasma-manager";
      inputs.nixpkgs.follows = "nixpkgs";
      inputs.home-manager.follows = "home-manager";
    };

    plasma-manager-unstable = {
      url = "github:nix-community/plasma-manager";
      inputs.nixpkgs.follows = "nixpkgs-unstable";
      inputs.home-manager.follows = "home-manager-unstable";
    };

    google-cookie-retrieval = {
      url = "git+https://git.johnogle.info/johno/google-cookie-retrieval.git";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    jovian = {
      url = "github:Jovian-Experiments/Jovian-NixOS";
      inputs.nixpkgs.follows = "nixpkgs-unstable";
    };

    beads = {
      url = "github:steveyegge/beads";
      inputs.nixpkgs.follows = "nixpkgs-unstable";
    };

    gastown = {
      url = "github:steveyegge/gastown";
      inputs.nixpkgs.follows = "nixpkgs-unstable";
      inputs.beads.follows = "beads";
    };

    perles = {
      url = "github:zjrosen/perles";
      flake = false;  # No flake.nix upstream yet
    };

    nix-doom-emacs-unstraightened = {
      url = "github:marienz/nix-doom-emacs-unstraightened";
      # Don't follow nixpkgs to avoid rebuild issues with emacs-overlay
      inputs.nixpkgs.follows = "";
    };
  };

  outputs = { self, nixpkgs, nixpkgs-unstable, ... } @ inputs: let
    # Shared overlay function to reduce duplication across module sets
    # Parameters:
    #   unstableOverlays: Additional overlays to apply when importing nixpkgs-unstable
    mkBaseOverlay = { unstableOverlays ? [] }: (final: prev: {
      unstable = import nixpkgs-unstable {
        system = prev.stdenv.hostPlatform.system;
        config.allowUnfree = true;
        overlays = unstableOverlays;
      };
      # Separate nixpkgs for qt5webengine-heavy packages to avoid rebuild churn
      qt-pinned = import inputs.nixpkgs-qt {
        system = prev.stdenv.hostPlatform.system;
        config = {
          allowUnfree = true;
          permittedInsecurePackages = [ "qtwebengine-5.15.19" ];
        };
      };
      custom = prev.callPackage ./packages {};
      # Compatibility: bitwarden renamed to bitwarden-desktop in unstable
      bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
    });

    # Shared home-manager configuration factory
    # Parameters:
    #   sharedModules: Additional modules to include in home-manager.sharedModules
    mkHomeManagerConfig = { sharedModules ? [] }: {
      home-manager.useGlobalPkgs = true;
      home-manager.useUserPackages = true;
      home-manager.sharedModules = sharedModules ++ [
        inputs.nix-doom-emacs-unstraightened.homeModule
      ];
      home-manager.extraSpecialArgs = {
        globalInputs = inputs;
      };
    };


    # Shared unstable overlays for custom package builds
    customUnstableOverlays = [
      # Override claude-code in unstable to use our custom GCS-based build
      # (needed for corporate networks that block npm registry)
      (ufinal: uprev: {
        claude-code = uprev.callPackage ./packages/claude-code {};
      })
      # Pin dolt to v1.82.4 (gastown requires >= 1.82.4)
      (ufinal: uprev: {
        dolt = uprev.dolt.overrideAttrs (old: rec {
          version = "1.82.4";
          src = uprev.fetchFromGitHub {
            owner = "dolthub";
            repo = "dolt";
            tag = "v${version}";
            hash = "sha256-mavL3y+Kv25hzFlDFXk7W/jeKVKlCBjlc67GkL3Jcwk=";
          };
          vendorHash = "sha256-K1KzsqptZxO5OraWKIXeqKuVSzb6E/Mjy3c5PQ7Rs9k=";
        });
      })
    ];

    nixosModules = [
      ./roles
      inputs.home-manager.nixosModules.home-manager
      {
        nixpkgs.overlays = [ (mkBaseOverlay { unstableOverlays = customUnstableOverlays; }) ];
      }
      (mkHomeManagerConfig {
        sharedModules = [ inputs.plasma-manager.homeModules.plasma-manager ];
      })
    ];

    # Modules for unstable-based systems (like nix-deck)
    nixosModulesUnstable = [
      ./roles
      inputs.home-manager-unstable.nixosModules.home-manager
      inputs.jovian.nixosModules.jovian
      {
        nixpkgs.overlays = [ (mkBaseOverlay { unstableOverlays = customUnstableOverlays; }) ];
      }
      (mkHomeManagerConfig {
        sharedModules = [ inputs.plasma-manager-unstable.homeModules.plasma-manager ];
      })
    ];

    darwinModules = [
      ./roles/darwin.nix
      inputs.home-manager.darwinModules.home-manager
      {
        nixpkgs.overlays = [ (mkBaseOverlay { unstableOverlays = customUnstableOverlays; }) ];
      }
      (mkHomeManagerConfig { sharedModules = []; })
    ];

  in {
    nixosConfigurations.nix-book = nixpkgs.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModules ++ [
        ./machines/nix-book/configuration.nix
        {
          home-manager.users.johno = {
            imports = [ ./home/home-laptop-compact.nix ];
            # Machine-specific overrides
            home.roles.i3_sway.extraSwayConfig = {
              output.eDP-1.scale = "1.75";
            };
          };
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    nixosConfigurations.boxy = nixpkgs.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModules ++ [
        ./machines/boxy/configuration.nix
        {
          home-manager.users.johno = import ./home/home-media-center.nix;
          # kodi user: AVR volume control + minimal Plasma config for Bigscreen session
          home-manager.users.kodi = import ./home/home-kodi.nix;
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    nixosConfigurations.zix790prors = nixpkgs.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModules ++ [
        ./machines/zix790prors/configuration.nix
        {
          home-manager.users.johno = {
            imports = [ ./home/home-desktop.nix ];
            home.roles.i3_sway.extraSwayConfig = {
              output = {
                "DP-1" = {
                  mode = "3440x1440@164.900Hz";
                };
              };
            };
          };
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    # Live USB ISO configuration
    nixosConfigurations.live-usb = nixpkgs.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModules ++ [
        ./machines/live-usb/configuration.nix
        {
          home-manager.users.nixos = import ./home/home-live-usb.nix;
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    # Steam Deck configuration (using unstable for better Jovian compatibility)
    nixosConfigurations.nix-deck = nixpkgs-unstable.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModulesUnstable ++ [
        ./machines/nix-deck/configuration.nix
        {
          home-manager.users.johno = import ./home/home-desktop.nix;
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    # ZFS/NFS server configuration
    nixosConfigurations.john-endesktop = nixpkgs.lib.nixosSystem rec {
      system = "x86_64-linux";
      modules = nixosModules ++ [
        ./machines/john-endesktop/configuration.nix
        inputs.home-manager.nixosModules.home-manager
        {
          home-manager.users.johno = import ./home/home-server.nix;
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    # Darwin/macOS configurations
    darwinConfigurations."BLKFV4YF49KT7" = inputs.nix-darwin.lib.darwinSystem rec {
      system = "aarch64-darwin";
      modules = darwinModules ++ [
        ./machines/johno-macbookpro/configuration.nix
        {
          home-manager.users.johno = import ./home/home-darwin-work.nix;
          home-manager.extraSpecialArgs = { inherit system; };
        }
      ];
    };

    # Packages for CI caching (custom packages, flake inputs, and qt-pinned)
    packages = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          config.allowUnfree = true;
          overlays = [ (mkBaseOverlay {}) ];
        };
        pkgsQt = import inputs.nixpkgs-qt {
          inherit system;
          config = {
            allowUnfree = true;
            permittedInsecurePackages = [ "qtwebengine-5.15.19" ];
          };
        };
        # Version strings for flake input packages
        beadsRev = builtins.substring 0 8 (inputs.beads.rev or "unknown");
        gastownRev = builtins.substring 0 8 (inputs.gastown.rev or "unknown");
      in {
        "custom-claude-code" = pkgs.custom.claude-code;
        "custom-app-launcher-server" = pkgs.custom.app-launcher-server;
        "custom-mcrcon-rbw" = pkgs.custom.mcrcon-rbw;
        "custom-tea-rbw" = pkgs.custom.tea-rbw;
        "custom-rclone-torbox-setup" = pkgs.custom.rclone-torbox-setup;
        "qt-pinned-jellyfin-media-player" = pkgsQt.jellyfin-media-player;
        "qt-pinned-stremio" = pkgsQt.stremio;
        # Flake input packages (beads, gastown) - these get version from input rev
        "custom-beads" = pkgs.callPackage ./packages/beads {
          inherit (pkgs.unstable) buildGoModule;
          src = inputs.beads;
          version = "0.52.0-${beadsRev}";
        };
        "custom-gastown" = pkgs.callPackage ./packages/gastown {
          src = inputs.gastown;
          version = "unstable-${gastownRev}";
        };
        "custom-perles" = pkgs.callPackage ./packages/perles {
          inherit (pkgs.unstable) buildGoModule;
          src = inputs.perles;
          version = "unstable-${builtins.substring 0 8 (inputs.perles.rev or "unknown")}";
        };
      } // (if system == "x86_64-linux" then {
        # nix-deck kernel from Jovian-NixOS (Steam Deck) - expensive to build
        "nix-deck-kernel" = self.nixosConfigurations.nix-deck.config.boot.kernelPackages.kernel;
      } else {})
    );

    # Flake apps
    apps = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ] (system:
      let
        pkgs = import nixpkgs { inherit system; };
        commonDeps = [ pkgs.curl pkgs.jq pkgs.nix pkgs.git pkgs.gnused pkgs.gnugrep pkgs.coreutils pkgs.gawk ];

        update-doomemacs = pkgs.writeShellScriptBin "update-doomemacs" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./scripts/update-doomemacs.sh}
        '';

        update-claude-code = pkgs.writeShellScriptBin "update-claude-code" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./packages/claude-code/update.sh}
        '';

        rotate-wallpaper = pkgs.writeShellScriptBin "rotate-wallpaper" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./scripts/rotate-wallpaper.sh}
        '';

        upgrade = pkgs.writeShellScriptBin "upgrade" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./scripts/upgrade.sh}
        '';

        bootstrap = pkgs.writeShellScriptBin "bootstrap" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./scripts/bootstrap.sh}
        '';

        build-liveusb = pkgs.writeShellScriptBin "build-liveusb" ''
          export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
          ${builtins.readFile ./scripts/build-liveusb.sh}
        '';
      in {
        update-doomemacs = {
          type = "app";
          program = "${update-doomemacs}/bin/update-doomemacs";
        };
        update-claude-code = {
          type = "app";
          program = "${update-claude-code}/bin/update-claude-code";
        };
        rotate-wallpaper = {
          type = "app";
          program = "${rotate-wallpaper}/bin/rotate-wallpaper";
        };
        upgrade = {
          type = "app";
          program = "${upgrade}/bin/upgrade";
        };
        bootstrap = {
          type = "app";
          program = "${bootstrap}/bin/bootstrap";
        };
        build-liveusb = {
          type = "app";
          program = "${build-liveusb}/bin/build-liveusb";
        };
      }
    );
  };
}
