# See morph/grid/local/grid.nix for additional commentary.
let
  pkgs = import <nixpkgs> { };

  gridlib = import ../../lib;
  rawConfig = pkgs.lib.trivial.importJSON ./config.json;
  config = rawConfig // {
    sshUsers = import ./public-keys/users.nix;

    # Convert relative paths to absolute so library code can resolve names
    # correctly.
    publicKeyPath = toString ./. + "/${rawConfig.publicKeyPath}";
    privateKeyPath = toString ./. + "/${rawConfig.privateKeyPath}";
  };

  payments = {
    imports = [
      gridlib.issuer
      gridlib.hardware-aws
      (gridlib.customize-issuer (config // {
        monitoringvpnIPv4 = "172.23.23.11";
      }))
    ];
    services.private-storage.monitoring.grafana.googleOAuthClientID = "";
    services.private-storage.monitoring.grafana.googleOAuthClientSecretFile = /run/keys/grafana-google-sso.secret;
  };

  monitoring = {
    imports = [
      gridlib.monitoring
      gridlib.hardware-aws
      (gridlib.customize-monitoring {
        inherit hostsMap vpnClientIPs nodeExporterTargets paymentExporterTargets;
        inherit (config) domain publicKeyPath privateKeyPath letsEncryptAdminEmail;
        monitoringvpnIPv4 = "172.23.23.1";
        stateVersion = "19.09";
      })
    ];
  };

  defineStorageNode = name: { vpnIP, stateVersion }:
  let
    nodecfg = import "${./.}/${name}-config.nix";
    hardware ="${./.}/${name}-hardware.nix";
  in {
    imports = [
      # Get some of the very lowest-level system configuration for this
      # node.  This isn't all *completely* hardware related.  Maybe some
      # more factoring is in order, someday.
      hardware

      # Slightly awkwardly, enable some of our hardware / network / bootloader options.
      ../../../nixos/modules/100tb.nix

      # Get all of the configuration that is common across all storage nodes.
      gridlib.storage

      # Then customize the storage system a little bit based on this node's particulars.
      (gridlib.customize-storage (config // nodecfg // {
        monitoringvpnIPv4 = vpnIP;
        inherit stateVersion;
      }))
    ];

    # And supply configuration for those hardware / network / bootloader
    # options.  See the 100tb module for handling of this value.  The module
    # name is quoted because `1` makes `100tb` look an awful lot like a
    # number.
   "100tb".config = nodecfg;
  };

  # Define all of the storage nodes for this grid.
  storageNodes = builtins.mapAttrs defineStorageNode {
    storage001 = { vpnIP = "172.23.23.21"; stateVersion = "19.09"; };
    storage002 = { vpnIP = "172.23.23.22"; stateVersion = "19.09"; };
    storage003 = { vpnIP = "172.23.23.23"; stateVersion = "19.09"; };
    storage004 = { vpnIP = "172.23.23.24"; stateVersion = "19.09"; };
    storage005 = { vpnIP = "172.23.23.25"; stateVersion = "19.03"; };
  };

  # TBD: derive these automatically:
  hostsMap = {
    "172.23.23.1"  = [ "monitoring" "monitoring.monitoringvpn" ];
    "172.23.23.11" = [   "payments"   "payments.monitoringvpn" ];
    "172.23.23.21" = [ "storage001" "storage001.monitoringvpn" ];
    "172.23.23.22" = [ "storage002" "storage002.monitoringvpn" ];
    "172.23.23.23" = [ "storage003" "storage003.monitoringvpn" ];
    "172.23.23.24" = [ "storage004" "storage004.monitoringvpn" ];
    "172.23.23.25" = [ "storage005" "storage005.monitoringvpn" ];
  };
  vpnClientIPs = [
    "172.23.23.11"
    "172.23.23.21"
    "172.23.23.22"
    "172.23.23.23"
    "172.23.23.24"
    "172.23.23.25"
  ];
  nodeExporterTargets = [
    "monitoring"
    "payments"
    "storage001"
    "storage002"
    "storage003"
    "storage004"
    "storage005"
  ];
  paymentExporterTargets = [ "payments" ];

in {
  network = {
    description = "PrivateStorage.io Production Grid";
  };
  inherit payments;
  inherit monitoring;
} // storageNodes