{ lib, ... }:
let
  attrList = lib.mkOption {
    type = lib.types.attrsOf lib.types.str;
  };
  boolType = lib.mkOption {
    type = lib.types.bool;
  };
  stringType = lib.mkOption {
    type = lib.types.str;
  };
  intType = lib.mkOption {
    type = lib.types.int;
  };
  listType = lib.mkOption {
    type = lib.types.listOf lib.types.str;
  };

  numOptions = 20;

  genOptions =
    config: prefix:
    builtins.listToAttrs (
      map (i: {
        name = "${prefix}${toString i}";
        value = config;
      }) (builtins.genList (i: i) numOptions)
    );

  mkOptionsFromDir =
    path:
    builtins.listToAttrs (
      map
        (name: {
          name = builtins.substring 0 (builtins.stringLength name - 4) name;
          value = stringType;
        })
        (
          builtins.filter (name: builtins.match ".*\\.nix$" name != null) (
            builtins.attrNames (builtins.readDir path)
          )
        )
    );

  userSubmodule = lib.types.submodule {
    options = {
      name = stringType;
      label = stringType;
      sshKeys = listType;
      group = stringType;
      aliases = genOptions stringType "name";
      email = genOptions stringType "address";
      paths = genOptions stringType "path";
    };
  };

  instanceSubmodule = lib.types.submodule {
    options = {
      subdomain = stringType;
      label = stringType;
      name = stringType;
      short = stringType;
      hostname = stringType;
      tags = listType;
      records = genOptions stringType "record";
      domains = genOptions stringType "url";
      dns = genOptions stringType "provider";
      localhost = genOptions stringType "address";
      wireguard = genOptions stringType "interface";
      remotehost = genOptions stringType "address";
      email = genOptions stringType "address";
      sops = genOptions stringType "path";
      paths = genOptions stringType "path";
      varPaths = genOptions stringType "path";
      mntPaths = genOptions stringType "path";
      secretPaths = genOptions stringType "path";
      ports = genOptions intType "port";
      interface = {
        id = stringType;
        mac = stringType;
        idUser = stringType;
        macUser = stringType;
        ip = stringType;
        gate = stringType;
        ssh = intType;
      };
      ssl = {
        cert = stringType;
        key = stringType;
        path = stringType;
      };
    };
  };

  deviceSubmodule = lib.types.submodule {
    options =
      let
        mountConfig = {
          mount = stringType;
          device = stringType;
          options = listType;
        };
      in
      {
        boot = mountConfig;
        ip = genOptions stringType "address";
        label = stringType;
        name = stringType;
        short = stringType;
        sync = genOptions stringType "address";
        wireguard = genOptions stringType "ip";
      }
      // genOptions mountConfig "folder"
      // genOptions mountConfig "samba"
      // genOptions mountConfig "remote"
      // genOptions mountConfig "storage";
  };

  themesSubmodule = lib.types.submodule {
    options = {
      currentTheme = stringType;
      windowManager = {
        gaps = intType;
        borders = intType;
        rounding = intType;
        enabled = {
          hyprland = boolType;
          niri = boolType;
        };
      };
      fonts = {
        name = stringType;
        sizes = {
          applications = intType;
          desktop = intType;
          popups = intType;
          terminal = intType;
        };
      };
      cursor = {
        name = stringType;
        size = intType;
      };
      palettes = lib.mkOption {
        type = lib.types.attrsOf (
          lib.types.submodule {
            options = {
              colours = attrList;
              font = stringType;
            };
          }
        );
      };

    };
  };
in
{
  options = {
    services = lib.mkOption {
      type = lib.types.submodule {
        options = mkOptionsFromDir ./instances/config // {
          instances = lib.mkOption {
            type = lib.types.attrsOf instanceSubmodule;
          };
        };
      };
    };
    machines = lib.mkOption {
      type = lib.types.submodule {
        options =
          let
            devicesPath = ./devices/config;
            printerPath = devicesPath + /printers;
          in
          mkOptionsFromDir devicesPath
          // mkOptionsFromDir printerPath
          // {
            devices = lib.mkOption {
              type = lib.types.attrsOf deviceSubmodule;
            };
          };
      };
    };
    people = lib.mkOption {
      type = lib.types.submodule {
        options = mkOptionsFromDir ./users/config // {
          users = lib.mkOption {
            type = lib.types.attrsOf userSubmodule;
          };
        };
      };
    };
    aesthetics = lib.mkOption {
      type = lib.types.submodule {
        options = mkOptionsFromDir ./themes // {
          themes = lib.mkOption {
            type = themesSubmodule;
          };
        };
      };
    };
  };

  config =
    let
      moduleFunctions = {
        devicesFunctions = {
          ownerWriteOthersReadMask = [
            "fmask=0022"
            "dmask=0022"
          ];
          ownerExclusiveReadWriteMask = [
            "fmask=0077"
            "dmask=0077"
          ];
          readWritePermissions = [
            "rw"
          ];
          sambaPermissions = [
            "rw"
            "gid=100"
            "vers=3.0"
            "x-systemd.automount"
            "x-systemd.requires=network-online.target"
          ];
          sshfsOptions = [
            "allow_other"
            "_netdev"
            "x-systemd.automount"
            "reconnect"
            "user"
            "ServerAliveInterval=15"
            "IdentityFile=/var/run/secrets/ssh/private"
          ];
          fileModeAndDirMode = [
            "file_mode=0644"
            "dir_mode=0755"
          ];
          userIdForUser0 = [
            "uid=1000"
          ];
          dummy = [
          ];

          ceresStorageDriveName = "NAS1";
          erisStorageDriveName = "NAS2";
          ceresIP = "192.168.50.240";
          erisIP = "192.168.50.245";
          deimosIP = "192.168.50.176";
          marsIP = "192.168.50.218";
          phoneIP = "192.168.50.243";
          phobosIP = "192.168.50.194";
          brotherIP = "192.168.50.195";
          externalIP = "24.76.173.0";
          lamdagibsonIP = "192.168.50.131";

          deviceNames = {
            desktop = "mars";
            desktopLabel = "Mars";
            server = "ceres";
            serverLabel = "Ceres";
            eris = "eris";
            erisLabel = "Eris";
            laptop = "deimos";
            laptopLabel = "Deimos";
            laptop2 = "phobos";
            laptop2Label = "Phobos";
            phone = "pixel";
            phoneLabel = "Pixel";
            iso = "iso";
            isoLabel = "Iso";
          };

        };

        instancesFunctions =
          let
            var = "/var/lib";
          in
          {
            domain0 = "cloudbert.fun";
            domain1 = "uprootnutrition.com";
            emailNoReply = "noreply";
            servicePath = "/mnt/media/NAS1";
            mntPath = "/mnt/storage";
            varLib = var;
            varPath = var;
            sslPath = "${var}/acme";
            sopsPath = "${var}/secrets";
            secretPath = "/run/secrets";
            cachePath = "/var/cache";
            dummy = "";
          };

        themesFunctions = {
          brogrammer = "brogrammer";
          catppuccin-frappe = "catppuccin-frappe";
          catppuccin-latte = "catppuccin-latte";
          catppuccin-macchiato = "catppuccin-macchiato";
          catppuccin-mocha = "catppuccin-mocha";
          chalk = "chalk";
          deep-oceanic-next = "deep-oceanic-next";
          dracula = "dracula";
          espresso = "espresso";
          flat = "flat";
          framer = "framer";
          github = "github";
          hardcore = "hardcore";
          one-black = "one-black";
          one-dark = "one-dark";
          one-light = "one light";
          sparky = "sparky";
        };

        usersFunctions = {
          user0 = "nick";
          user0Label = "Nick";
        };
      };

      inheritFunctions = { inherit moduleFunctions; };
    in
    {
      people = import ./users inheritFunctions;
      services = import ./instances inheritFunctions;
      machines = import ./devices inheritFunctions;
      aesthetics = import ./themes inheritFunctions;
    };
}
