{ config, lib, ... }:

with builtins;
with lib;

let
  cfg = config.machine;
  fn = import (toString ../fn.nix) { inherit lib; };
  metapkgs = let
    pPath = (toString ../pkgsets);
  in (lists.forEach (fn.lsfRec pPath true) (v: replaceStrings [ "${pPath}/" "/" ".nix" ] [ "" "::" "" ] v));
  pkgOption = pname: {
    name = pname;
    value = rec {
      pkgwrap = mkOption {
        type = with types; oneOf [ package (listOf package) ];
        default = (fn.pkgFilter cfg.pkgsets."${pname}".pkgs);
        description = ''
          Package Wrapper for packages using a wrapper function (like python, emacs, haskell, ...)
        '';
      };
      pkgs = mkOption {
        type = types.unspecified;
        default = [];
        description = ''
          ${pname} package list.
        '';
      };
    };
  };
in {
  options.machine = {
    pkgs = mkOption {
      type = (types.listOf (types.enum metapkgs));
      default = [ "base" ];
      description = ''
        The list of metapackages to be installed.
      '';
    };
    # Package names containing '::' are sub packages and should not have their own pkgset.
    pkgsets = listToAttrs (map pkgOption (lists.filter (v: !(strings.hasInfix "::" v)) metapkgs));
    services = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        List of services to be enabled.
      '';
    };
    conffiles = mkOption {
      type = types.listOf types.str;
      default = [ "zsh" ];
      description = ''
        List of configuration files to be enabled.
      '';
    };
    hostName = mkOption {
      type = types.str;
      description = ''
        The Machines HostName
      '';
    };
    useNetworkd = mkOption {
      type = types.bool;
      default = false;
      description = ''
        Disables dhcpcd and enables networkd.
      '';
    };
    binaryCaches = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        Adds binary caches to both nix.trustedBinaryCaches and nix.binaryCaches. ("https://cache.nixos.org" is kept by default)
      '';
    };
    secretPath = mkOption {
      type = types.str;
      default = let sPathVal = (tryEval <secretPath>).value;
                in fn.ifelse (sPathVal != false) sPathVal "/secret";
      description = ''
        Path to you systems secret folder containing files with sensitive information.
      '';
    };
    administrators = mkOption {
      type = types.listOf types.attrs;
      description = ''
        List of administrative users.
      '';
    };
    domain = mkOption {
      type = types.str;
      default = "localhost";
      description = ''
        The Machines domain name.
      '';
    };
    extraDomains = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        Extra domains used in various services.
      '';
    };
    mailAccounts = mkOption {
      type = types.listOf types.attrs;
      default = [];
      description = ''
        List of mail account user names.
      '';
    };
    vHosts = mkOption {
      type = types.listOf types.attrs;
      default = [];
      description = ''
        Domain - Service mappings for nginx vHost config.
      '';
    };
    desktop.wms = mkOption {
      type = types.listOf types.str;
      default = [];
      description = ''
        The list of wms to be enabled.
      '';
    };
  };
  imports = [
    (mkAliasOptionModule [ "machine" "firewall" ] [ "networking" "firewall" ])
    (mkAliasOptionModule [ "machine" "allowUnfree" ] [ "nixpkgs" "config" "allowUnfree" ])
  ];
}