{ nixpkgs ? import ./Bild/Nixpkgs.nix }:

let
  constants = import ./Bild/Constants.nix;
  lib = nixpkgs.lib;
# put all of our stuff in the 'bild' namespace
in nixpkgs // { bild = rec {
  # provided by .envrc
  root = builtins.getEnv "BIZ_ROOT";

  inherit (nixpkgs) sources;

  haskell = rec {
    inherit (constants) ghcCompiler;

    # all available packages
    deps = import ./Bild/Deps/Haskell.nix;
    packages = lib.attrsets.getAttrs deps nixpkgs.haskellPackages;

    # make a ghc with dependencies
    ghcWith = nixpkgs.haskell.packages.${ghcCompiler}.ghcWithHoogle;

    # ghc with all packages, used for generating bild's package database
    ghcPackageSetFull = ghcWith (p: lib.attrsets.attrVals deps p);

    # bild's dependencies, needs to be hand-written
    ghcPackageSetBild = ghcWith (hpkgs: with hpkgs; [
      aeson async base bytestring conduit conduit-extra containers directory
      docopt filepath process protolude rainbow regex-applicative split tasty
      tasty-hunit tasty-quickcheck text hostname
      wai # can remove when removed from Biz.Log
    ]);
  };

  lisp = {
    sbclWith = nixpkgs.lispPackages_new.sbclWithPackages;
  };

  python = {
    packages = nixpkgs.python3Packages;
    pythonWith = nixpkgs.python3.withPackages;
    buildPythonApplication = nixpkgs.python3.pkgs.buildPythonApplication;
  };

  # c packages are just nixpkgs, filtered to just the list of deps i want
  c.packages = lib.attrsets.getAttrs (import ./Bild/Deps/C.nix) nixpkgs.pkgs;

  # expose some packages for inclusion in os/image builds
  pkgs = with nixpkgs.pkgs; { inherit git; };

  # this is needed to do builds without calling out to nix, remove this when I
  # switch to all-nix builds
  bildRuntimeDeps = with nixpkgs; [
    pkg-config
    # this is just to get access to ghc-pkg in bild
    (haskell.ghcWith (_: []))

    # lisp deps
    guile
    (lisp.sbclWith (p: with p; [asdf alexandria])) # just enough to build Example.lisp
  ];

  # a standard nix build for bild, for bootstrapping. this should be the only
  # hand-written builder we need
  bild = nixpkgs.stdenv.mkDerivation {
    name = "bild";
    src = ../.;
    nativeBuildInputs = [ haskell.ghcPackageSetBild ];
    buildInputs = [ nixpkgs.makeWrapper ];
    propagatedBuildInputs = bildRuntimeDeps;
    strictDeps = true;
    buildPhase = ''
      mkdir -p $out/bin $out/lib/ghc-${haskell.ghcPackageSetFull.version}
      cp -r \
        ${haskell.ghcPackageSetFull}/lib/ghc-${haskell.ghcPackageSetFull.version}/package.conf.d \
        $out/lib/ghc-${haskell.ghcPackageSetFull.version}
      ghc \
        -threaded \
        -Werror \
        -i. \
        --make Biz/Bild.hs \
        -main-is Biz.Bild \
        -o $out/bin/bild
    '';
    installPhase = ''
      wrapProgram $out/bin/bild \
        --prefix PATH : ${lib.makeBinPath [ haskell.ghcPackageSetBild ]} \
        --set GHC_PACKAGE_PATH \
        $out/lib/ghc-${haskell.ghcPackageSetFull.version}/package.conf.d
    '';
  };

  # wrapper around bild
  runBildAnalyze = target: nixpkgs.stdenv.mkDerivation rec {
    name = "bild-analysis";
    src = ../.;
    USER = "nixbld";
    HOSTNAME = "nix-sandbox";
    # this is the default sandbox path where bild will be working:
    BIZ_ROOT = "/build/biz";
    # we need to remove the $src root because bild expects paths relative to the
    # working directory:
    TARGET = "." + lib.strings.removePrefix (toString src) (toString target);
    buildPhase = ''
      mkdir $out
      ${bild}/bin/bild --json "$TARGET" 1> $out/analysis.json \
        2> >(tee -a $out/stderr >&2)
    '';
    installPhase = "exit 0";
  };

  # gather data needed for compiling by analyzing the main module. returns the
  # json object of the build
  analyze = target: builtins.readFile (runBildAnalyze target + "/analysis.json");

  # this does a bild build for the given target, but entirely in nix. its kinda
  # like IFD, but not as costly, i think
  run = target: import ./Bild/Builder.nix { analysisJSON = analyze target; };

  # the main development environment
  env = nixpkgs.pkgs.mkShell {
    name = "bizdev";
    # this should just be dev tools
    buildInputs = with nixpkgs.pkgs; [
      bild
      black
      ctags
      figlet
      git
      gitlint
      lolcat
      nixpkgs.haskell.packages.${constants.ghcCompiler}.fast-tags
      ormolu
      wemux
    ];
    shellHook = ''
      export GHC_PACKAGE_PATH=${bild}/lib/ghc-${haskell.ghcPackageSetFull.version}/package.conf.d
    '';
  };

  # build an operating system. 'cfg' is the NixOS config
  os = cfg: (nixpkgs.nixos (_args: cfg)).toplevel;

  # build a docker image
  image = nixpkgs.pkgs.dockerTools.buildImage;
};
}