{ lib }:

with lib;

let
  mkInstallPlanType = types: types.submodule {
    options = {
      nixosConfiguration = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Name of the nixosConfigurations output to install";
      };

      diskoConfigPath = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Repository-relative Disko file used for installation";
      };

      targetDisk = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Explicit disk device path selected for installation";
      };

      targetDiskById = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Stable /dev/disk/by-id path selected for installation";
      };
    };
  };

  mkDesiredSystemType = types: types.submodule {
    options = {
      deploymentId = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional host deployment identifier owning this desired system";
      };

      nixosConfiguration = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Name of the nixosConfigurations output to activate";
      };

      targetSystem = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional prebuilt NixOS system closure path activated directly by nix-agent";
      };

      flakeRef = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Explicit flake reference used by nix-agent";
      };

      switchAction = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "switch-to-configuration action for nix-agent";
      };

      healthCheckCommand = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Command vector executed after activation to validate node health";
      };

      rollbackOnFailure = mkOption {
        type = types.nullOr types.bool;
        default = null;
        description = "Whether nix-agent should roll back when the health check fails";
      };

      drainBeforeApply = mkOption {
        type = types.nullOr types.bool;
        default = null;
        description = "Whether the controller should drain the node before issuing this desired system";
      };
    };
  };

  mkHostDeploymentSelectorType = types: types.submodule {
    options = {
      nodeIds = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Explicit node IDs targeted by the deployment";
      };

      roles = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Node roles targeted by the deployment";
      };

      pools = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Node pools targeted by the deployment";
      };

      nodeClasses = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Node classes targeted by the deployment";
      };

      matchLabels = mkOption {
        type = types.attrsOf types.str;
        default = { };
        description = "Label selectors applied to target nodes";
      };
    };
  };

  mkHostDeploymentType = types:
    let
      selectorType = mkHostDeploymentSelectorType types;
    in
    types.submodule {
      options = {
        selector = mkOption {
          type = selectorType;
          default = { };
          description = "Node selector used by the host deployment";
        };

        nixosConfiguration = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Name of the nixosConfigurations output to roll out";
        };

        targetSystem = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional prebuilt NixOS system closure path handed directly to nix-agent";
        };

        flakeRef = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Explicit flake reference used during rollout";
        };

        batchSize = mkOption {
          type = types.nullOr types.int;
          default = null;
          description = "Maximum number of nodes started per reconciliation wave";
        };

        maxUnavailable = mkOption {
          type = types.nullOr types.int;
          default = null;
          description = "Maximum number of unavailable nodes allowed during rollout";
        };

        healthCheckCommand = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Health check command executed by nix-agent after activation";
        };

        switchAction = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "switch-to-configuration action used by nix-agent";
        };

        rollbackOnFailure = mkOption {
          type = types.nullOr types.bool;
          default = null;
          description = "Whether nodes should roll back when rollout health checks fail";
        };

        drainBeforeApply = mkOption {
          type = types.nullOr types.bool;
          default = null;
          description = "Whether the controller should drain a node before applying the rollout";
        };

        rebootPolicy = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Operator-facing reboot policy associated with the rollout";
        };

        paused = mkOption {
          type = types.nullOr types.bool;
          default = null;
          description = "Whether the rollout should start in a paused state";
        };
      };
    };

  mkServicePortsType = types: types.submodule {
    options = {
      http = mkOption {
        type = types.nullOr types.port;
        default = null;
        description = "Optional HTTP port exposed by the service";
      };

      grpc = mkOption {
        type = types.nullOr types.port;
        default = null;
        description = "Optional gRPC port exposed by the service";
      };
    };
  };

  mkProcessType = types: types.submodule {
    options = {
      command = mkOption {
        type = types.str;
        description = "Executable invoked by node-agent";
      };

      args = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Command-line arguments passed to the process";
      };

      workingDir = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional working directory used when spawning the process";
      };

      env = mkOption {
        type = types.attrsOf types.str;
        default = { };
        description = "Environment variables injected into the process";
      };
    };
  };

  mkContainerPortType = types: types.submodule {
    options = {
      containerPort = mkOption {
        type = types.port;
        description = "Port exposed inside the container";
      };

      hostPort = mkOption {
        type = types.nullOr types.port;
        default = null;
        description = "Optional fixed host port published for this container port";
      };

      protocol = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional transport protocol for the published port";
      };
    };
  };

  mkContainerVolumeType = types: types.submodule {
    options = {
      source = mkOption {
        type = types.str;
        description = "Host-side volume source path";
      };

      target = mkOption {
        type = types.str;
        description = "Container mount target path";
      };

      readOnly = mkOption {
        type = types.bool;
        default = false;
        description = "Whether the volume should be mounted read-only";
      };
    };
  };

  mkContainerType = types:
    let
      containerPortType = mkContainerPortType types;
      containerVolumeType = mkContainerVolumeType types;
    in
    types.submodule {
      options = {
        image = mkOption {
          type = types.str;
          description = "Container image reference";
        };

        runtime = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Container runtime invoked by node-agent";
        };

        command = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Optional entrypoint override";
        };

        args = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Container arguments appended after the image";
        };

        env = mkOption {
          type = types.attrsOf types.str;
          default = { };
          description = "Environment variables passed to the container runtime";
        };

        ports = mkOption {
          type = types.listOf containerPortType;
          default = [ ];
          description = "Published container ports";
        };

        volumes = mkOption {
          type = types.listOf containerVolumeType;
          default = [ ];
          description = "Host volume mounts passed to the container runtime";
        };

        networkMode = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional container network mode";
        };

        pullPolicy = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Container image pull policy";
        };

        workingDir = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional container working directory";
        };
      };
    };

  mkHealthCheckType = types: types.submodule {
    options = {
      type = mkOption {
        type = types.str;
        description = "Health check type executed by node-agent";
      };

      path = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional path used by HTTP health checks";
      };

      intervalSecs = mkOption {
        type = types.nullOr types.ints.positive;
        default = null;
        description = "Health check interval in seconds";
      };

      timeoutSecs = mkOption {
        type = types.nullOr types.ints.positive;
        default = null;
        description = "Health check timeout in seconds";
      };

      startupGraceSecs = mkOption {
        type = types.nullOr types.ints.positive;
        default = null;
        description = "Startup grace period before a service is considered unhealthy";
      };
    };
  };

  mkPlacementPolicyType = types: types.submodule {
    options = {
      roles = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Roles matched by the scheduler placement filter";
      };

      pools = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Pools matched by the scheduler placement filter";
      };

      nodeClasses = mkOption {
        type = types.listOf types.str;
        default = [ ];
        description = "Node classes matched by the scheduler placement filter";
      };

      matchLabels = mkOption {
        type = types.attrsOf types.str;
        default = { };
        description = "Additional label selectors matched by the scheduler";
      };

      spreadByLabel = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional spread key used when balancing replicas";
      };

      maxInstancesPerNode = mkOption {
        type = types.ints.positive;
        default = 1;
        description = "Maximum number of replicas the scheduler may place on one node";
      };
    };
  };

  mkRolloutStrategyType = types: types.submodule {
    options = {
      maxUnavailable = mkOption {
        type = types.ints.unsigned;
        default = 1;
        description = "Maximum unavailable instances allowed during a rollout";
      };

      maxSurge = mkOption {
        type = types.ints.unsigned;
        default = 1;
        description = "Maximum extra instances allowed during a rollout";
      };
    };
  };

  mkServiceScheduleType = types:
    let
      placementPolicyType = mkPlacementPolicyType types;
      rolloutStrategyType = mkRolloutStrategyType types;
      processType = mkProcessType types;
      containerType = mkContainerType types;
      healthCheckType = mkHealthCheckType types;
    in
    types.submodule {
      options = {
        mode = mkOption {
          type = types.enum [ "replicated" "daemon" ];
          default = "replicated";
          description = "Scheduling mode used by the native runtime service";
        };

        replicas = mkOption {
          type = types.ints.positive;
          default = 1;
          description = "Desired number of scheduler-managed replicas";
        };

        placement = mkOption {
          type = placementPolicyType;
          default = { };
          description = "Scheduler placement rules for the service";
        };

        rollout = mkOption {
          type = rolloutStrategyType;
          default = { };
          description = "Rollout budget used by the scheduler";
        };

        instancePort = mkOption {
          type = types.nullOr types.port;
          default = null;
          description = "Host port used when creating service instances";
        };

        meshPort = mkOption {
          type = types.nullOr types.port;
          default = null;
          description = "Optional service mesh port for the managed instances";
        };

        process = mkOption {
          type = types.nullOr processType;
          default = null;
          description = "Process-based runtime specification";
        };

        container = mkOption {
          type = types.nullOr containerType;
          default = null;
          description = "Container-based runtime specification";
        };

        healthCheck = mkOption {
          type = types.nullOr healthCheckType;
          default = null;
          description = "Health check performed by node-agent";
        };
      };
    };

  mkDnsPublicationType = types: types.submodule {
    options = {
      zone = mkOption {
        type = types.str;
        description = "FlashDNS zone used for service publication";
      };

      name = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional record name inside the published zone";
      };

      ttl = mkOption {
        type = types.ints.positive;
        default = 30;
        description = "DNS TTL for the published record";
      };

      mode = mkOption {
        type = types.enum [ "load_balancer" "direct" "direct_multi" ];
        default = "load_balancer";
        description = "Whether DNS publishes the load balancer VIP or a direct instance address";
      };
    };
  };

  mkLoadBalancerPublicationType = types: types.submodule {
    options = {
      orgId = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional organization used when provisioning FiberLB resources";
      };

      projectId = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional project used when provisioning FiberLB resources";
      };

      name = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional explicit load balancer name";
      };

      listenerPort = mkOption {
        type = types.nullOr types.port;
        default = null;
        description = "Listener port exposed by the load balancer";
      };

      protocol = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Listener protocol for the published load balancer";
      };

      poolProtocol = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Backend pool protocol for the published load balancer";
      };
    };
  };

  mkServicePublicationType = types:
    let
      dnsPublicationType = mkDnsPublicationType types;
      loadBalancerPublicationType = mkLoadBalancerPublicationType types;
    in
    types.submodule {
      options = {
        orgId = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Default organization used for service publication";
        };

        projectId = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Default project used for service publication";
        };

        dns = mkOption {
          type = types.nullOr dnsPublicationType;
          default = null;
          description = "Optional FlashDNS publication target";
        };

        loadBalancer = mkOption {
          type = types.nullOr loadBalancerPublicationType;
          default = null;
          description = "Optional FiberLB publication target";
        };
      };
    };

  mkServiceType = types:
    let
      servicePortsType = mkServicePortsType types;
      serviceScheduleType = mkServiceScheduleType types;
      servicePublicationType = mkServicePublicationType types;
    in
    types.submodule {
      options = {
        ports = mkOption {
          type = types.nullOr servicePortsType;
          default = null;
          description = "Optional logical service ports";
        };

        protocol = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional service protocol";
        };

        mtlsRequired = mkOption {
          type = types.nullOr types.bool;
          default = null;
          description = "Whether service-to-service traffic requires mTLS";
        };

        meshMode = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional mesh publication mode";
        };

        schedule = mkOption {
          type = types.nullOr serviceScheduleType;
          default = null;
          description = "Scheduler-managed runtime intent";
        };

        publish = mkOption {
          type = types.nullOr servicePublicationType;
          default = null;
          description = "Optional publication targets for the service";
        };
      };
    };

  mkMtlsPolicyType = types: types.submodule {
    options = {
      environment = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional environment scope for the policy";
      };

      sourceService = mkOption {
        type = types.str;
        description = "Source service matched by the policy";
      };

      targetService = mkOption {
        type = types.str;
        description = "Target service matched by the policy";
      };

      mtlsRequired = mkOption {
        type = types.nullOr types.bool;
        default = null;
        description = "Whether the policy enforces mTLS";
      };

      mode = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Optional policy mode";
      };
    };
  };

  mkNodeType = types:
    let
      installPlanType = mkInstallPlanType types;
      desiredSystemType = mkDesiredSystemType types;
    in
    types.submodule {
      options = {
        role = mkOption {
          type = types.enum [ "control-plane" "worker" ];
          default = "worker";
          description = "Node role in the cluster";
        };

        ip = mkOption {
          type = types.str;
          description = "IP address of the node";
        };

        services = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Services to run on this node";
        };

        raftPort = mkOption {
          type = types.port;
          default = 2380;
          description = "Raft port for consensus protocols";
        };

        apiPort = mkOption {
          type = types.port;
          default = 2379;
          description = "API port for cluster services";
        };

        metadata = mkOption {
          type = types.attrsOf types.anything;
          default = { };
          description = "Additional metadata for the node";
        };

        machineId = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Stable machine-id used to pre-register the node with deployer";
        };

        labels = mkOption {
          type = types.attrsOf types.str;
          default = { };
          description = "User-defined labels exported into deployer cluster state";
        };

        pool = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Logical node pool exported into deployer cluster state";
        };

        nodeClass = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Reusable node class assigned to this node in deployer state";
        };

        failureDomain = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Failure domain / zone label exported into deployer cluster state";
        };

        nixProfile = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Desired Nix profile associated with the node";
        };

        installPlan = mkOption {
          type = types.nullOr installPlanType;
          default = null;
          description = "Explicit NixOS installation targets for bare-metal bootstrap";
        };

        desiredSystem = mkOption {
          type = types.nullOr desiredSystemType;
          default = null;
          description = "Desired NixOS reconciliation state exported for nix-agent";
        };

        state = mkOption {
          type = types.nullOr (types.enum [ "pending" "provisioning" "active" "failed" "draining" ]);
          default = null;
          description = "Desired deployer node lifecycle state";
        };

        commissionState = mkOption {
          type = types.nullOr (types.enum [ "discovered" "commissioning" "commissioned" ]);
          default = null;
          description = "Optional commissioning state exported into deployer cluster state";
        };

        installState = mkOption {
          type = types.nullOr (types.enum [ "pending" "installing" "installed" "failed" "reinstall_requested" ]);
          default = null;
          description = "Optional install lifecycle state exported into deployer cluster state";
        };

        powerState = mkOption {
          type = types.nullOr (types.enum [ "on" "off" "cycling" "unknown" ]);
          default = null;
          description = "Optional external power-management state associated with the node";
        };

        bmcRef = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional BMC / Redfish reference associated with the node";
        };
      };
    };

  mkNodeClassType = types:
    let
      installPlanType = mkInstallPlanType types;
    in
    types.submodule {
      options = {
        description = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Human-readable description of the node class";
        };

        nixProfile = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Desired Nix profile inherited by nodes in this class";
        };

        installPlan = mkOption {
          type = types.nullOr installPlanType;
          default = null;
          description = "Default install plan inherited by nodes in this class";
        };

        roles = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Roles inherited by nodes in this class";
        };

        labels = mkOption {
          type = types.attrsOf types.str;
          default = { };
          description = "Labels inherited by nodes in this class";
        };
      };
    };

  mkNodePoolType = types: types.submodule {
    options = {
      description = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Human-readable description of the node pool";
      };

      nodeClass = mkOption {
        type = types.nullOr types.str;
        default = null;
        description = "Default node class assigned to nodes in this pool";
      };

      minSize = mkOption {
        type = types.nullOr types.int;
        default = null;
        description = "Minimum desired pool size";
      };

      maxSize = mkOption {
        type = types.nullOr types.int;
        default = null;
        description = "Maximum desired pool size";
      };

      labels = mkOption {
        type = types.attrsOf types.str;
        default = { };
        description = "Labels applied to nodes in this pool";
      };
    };
  };

  mkEnrollmentRuleType = types:
    let
      installPlanType = mkInstallPlanType types;
    in
    types.submodule {
      options = {
        priority = mkOption {
          type = types.int;
          default = 0;
          description = "Higher priority rules win when multiple rules match";
        };

        matchLabels = mkOption {
          type = types.attrsOf types.str;
          default = { };
          description = "Label selectors matched against phone-home metadata";
        };

        matchHostnamePrefix = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Optional hostname prefix matched during enrollment";
        };

        matchIpPrefixes = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Optional IP prefixes matched during enrollment";
        };

        pool = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Pool assigned when the rule matches";
        };

        nodeClass = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Node class assigned when the rule matches";
        };

        role = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Primary role assigned when the rule matches";
        };

        labels = mkOption {
          type = types.attrsOf types.str;
          default = { };
          description = "Labels attached when the rule matches";
        };

        nixProfile = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Nix profile attached when the rule matches";
        };

        installPlan = mkOption {
          type = types.nullOr installPlanType;
          default = null;
          description = "Install plan attached when the rule matches";
        };

        services = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "Services enabled for matching nodes";
        };

        sshAuthorizedKeys = mkOption {
          type = types.listOf types.str;
          default = [ ];
          description = "SSH authorized keys installed for matching nodes";
        };

        nodeIdPrefix = mkOption {
          type = types.nullOr types.str;
          default = null;
          description = "Prefix used when synthesizing node IDs";
        };
      };
    };

  mkInstallPlan = plan:
    let
      rendered =
        optionalAttrs (plan != null && plan.nixosConfiguration != null)
          {
            nixos_configuration = plan.nixosConfiguration;
          }
        // optionalAttrs (plan != null && plan.diskoConfigPath != null) {
          disko_config_path = plan.diskoConfigPath;
        }
        // optionalAttrs (plan != null && plan.targetDisk != null) {
          target_disk = plan.targetDisk;
        }
        // optionalAttrs (plan != null && plan.targetDiskById != null) {
          target_disk_by_id = plan.targetDiskById;
        };
    in
    if plan == null || rendered == { } then null else rendered;

  mkDesiredSystem = nodeName: desiredSystem:
    let
      rendered =
        optionalAttrs (desiredSystem != null && desiredSystem.deploymentId != null)
          {
            deployment_id = desiredSystem.deploymentId;
          }
        // optionalAttrs (desiredSystem != null && desiredSystem.nixosConfiguration != null) {
          nixos_configuration = desiredSystem.nixosConfiguration;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.targetSystem != null) {
          target_system = desiredSystem.targetSystem;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.flakeRef != null) {
          flake_ref = desiredSystem.flakeRef;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.switchAction != null) {
          switch_action = desiredSystem.switchAction;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.healthCheckCommand != [ ]) {
          health_check_command = desiredSystem.healthCheckCommand;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.rollbackOnFailure != null) {
          rollback_on_failure = desiredSystem.rollbackOnFailure;
        }
        // optionalAttrs (desiredSystem != null && desiredSystem.drainBeforeApply != null) {
          drain_before_apply = desiredSystem.drainBeforeApply;
        };
    in
    if desiredSystem == null || rendered == { } then null else {
      node_id = nodeName;
    } // rendered;

  mkHostDeploymentSelector = selector:
    {
      node_ids = selector.nodeIds or [ ];
      roles = selector.roles or [ ];
      pools = selector.pools or [ ];
      node_classes = selector.nodeClasses or [ ];
      match_labels = selector.matchLabels or { };
    };

  mkDeployerHostDeploymentSpec = name: deployment:
    {
      inherit name;
      selector = mkHostDeploymentSelector deployment.selector;
    }
    // optionalAttrs (deployment.nixosConfiguration != null) {
      nixos_configuration = deployment.nixosConfiguration;
    }
    // optionalAttrs (deployment.targetSystem != null) {
      target_system = deployment.targetSystem;
    }
    // optionalAttrs (deployment.flakeRef != null) {
      flake_ref = deployment.flakeRef;
    }
    // optionalAttrs (deployment.batchSize != null) {
      batch_size = deployment.batchSize;
    }
    // optionalAttrs (deployment.maxUnavailable != null) {
      max_unavailable = deployment.maxUnavailable;
    }
    // optionalAttrs (deployment.healthCheckCommand != [ ]) {
      health_check_command = deployment.healthCheckCommand;
    }
    // optionalAttrs (deployment.switchAction != null) {
      switch_action = deployment.switchAction;
    }
    // optionalAttrs (deployment.rollbackOnFailure != null) {
      rollback_on_failure = deployment.rollbackOnFailure;
    }
    // optionalAttrs (deployment.drainBeforeApply != null) {
      drain_before_apply = deployment.drainBeforeApply;
    }
    // optionalAttrs (deployment.rebootPolicy != null) {
      reboot_policy = deployment.rebootPolicy;
    }
    // optionalAttrs (deployment.paused != null) {
      paused = deployment.paused;
    };

  mkDeployerNodeSpec = nodeName: node:
    {
      node_id = nodeName;
      hostname = nodeName;
      ip = node.ip;
      roles = unique [ node.role ];
      labels = node.labels;
    }
    // optionalAttrs (node.machineId != null) {
      machine_id = node.machineId;
    }
    // optionalAttrs (node.pool != null) {
      pool = node.pool;
    }
    // optionalAttrs (node.nodeClass != null) {
      node_class = node.nodeClass;
    }
    // optionalAttrs (node.failureDomain != null) {
      failure_domain = node.failureDomain;
    }
    // optionalAttrs (node.nixProfile != null) {
      nix_profile = node.nixProfile;
    }
    // optionalAttrs (mkInstallPlan node.installPlan != null) {
      install_plan = mkInstallPlan node.installPlan;
    }
    // optionalAttrs (mkDesiredSystem nodeName node.desiredSystem != null) {
      desired_system = mkDesiredSystem nodeName node.desiredSystem;
    }
    // optionalAttrs (node.state != null) {
      state = node.state;
    }
    // optionalAttrs (node.commissionState != null) {
      commission_state = node.commissionState;
    }
    // optionalAttrs (node.installState != null) {
      install_state = node.installState;
    }
    // optionalAttrs (node.powerState != null) {
      power_state = node.powerState;
    }
    // optionalAttrs (node.bmcRef != null) {
      bmc_ref = node.bmcRef;
    };

  mkDeployerNodeClassSpec = name: nodeClass:
    {
      inherit name;
      roles = nodeClass.roles;
      labels = nodeClass.labels;
    }
    // optionalAttrs (nodeClass.description != null) {
      description = nodeClass.description;
    }
    // optionalAttrs (nodeClass.nixProfile != null) {
      nix_profile = nodeClass.nixProfile;
    }
    // optionalAttrs (mkInstallPlan nodeClass.installPlan != null) {
      install_plan = mkInstallPlan nodeClass.installPlan;
    };

  mkDeployerPoolSpec = name: pool:
    {
      inherit name;
      labels = pool.labels;
    }
    // optionalAttrs (pool.description != null) {
      description = pool.description;
    }
    // optionalAttrs (pool.nodeClass != null) {
      node_class = pool.nodeClass;
    }
    // optionalAttrs (pool.minSize != null) {
      min_size = pool.minSize;
    }
    // optionalAttrs (pool.maxSize != null) {
      max_size = pool.maxSize;
    };

  mkDeployerEnrollmentRuleSpec = name: rule:
    {
      inherit name;
      priority = rule.priority;
      match_labels = rule.matchLabels;
      match_ip_prefixes = rule.matchIpPrefixes;
      labels = rule.labels;
      services = rule.services;
      ssh_authorized_keys = rule.sshAuthorizedKeys;
    }
    // optionalAttrs (rule.matchHostnamePrefix != null) {
      match_hostname_prefix = rule.matchHostnamePrefix;
    }
    // optionalAttrs (rule.pool != null) {
      pool = rule.pool;
    }
    // optionalAttrs (rule.nodeClass != null) {
      node_class = rule.nodeClass;
    }
    // optionalAttrs (rule.role != null) {
      role = rule.role;
    }
    // optionalAttrs (rule.nixProfile != null) {
      nix_profile = rule.nixProfile;
    }
    // optionalAttrs (mkInstallPlan rule.installPlan != null) {
      install_plan = mkInstallPlan rule.installPlan;
    }
    // optionalAttrs (rule.nodeIdPrefix != null) {
      node_id_prefix = rule.nodeIdPrefix;
    };

  mkServicePorts = ports:
    optionalAttrs (ports != null && ports.http != null)
      {
        http = ports.http;
      }
    // optionalAttrs (ports != null && ports.grpc != null) {
      grpc = ports.grpc;
    };

  mkProcessSpec = process:
    {
      command = process.command;
      args = process.args;
      env = process.env;
    }
    // optionalAttrs (process.workingDir != null) {
      working_dir = process.workingDir;
    };

  mkContainerPortSpec = port:
    {
      container_port = port.containerPort;
    }
    // optionalAttrs (port.hostPort != null) {
      host_port = port.hostPort;
    }
    // optionalAttrs (port.protocol != null) {
      protocol = port.protocol;
    };

  mkContainerVolumeSpec = volume:
    {
      source = volume.source;
      target = volume.target;
    }
    // optionalAttrs volume.readOnly {
      read_only = true;
    };

  mkContainerSpec = container:
    {
      image = container.image;
      command = container.command;
      args = container.args;
      env = container.env;
      ports = map mkContainerPortSpec container.ports;
      volumes = map mkContainerVolumeSpec container.volumes;
    }
    // optionalAttrs (container.runtime != null) {
      runtime = container.runtime;
    }
    // optionalAttrs (container.networkMode != null) {
      network_mode = container.networkMode;
    }
    // optionalAttrs (container.pullPolicy != null) {
      pull_policy = container.pullPolicy;
    }
    // optionalAttrs (container.workingDir != null) {
      working_dir = container.workingDir;
    };

  mkHealthCheckSpec = healthCheck:
    {
      type = healthCheck.type;
    }
    // optionalAttrs (healthCheck.path != null) {
      path = healthCheck.path;
    }
    // optionalAttrs (healthCheck.intervalSecs != null) {
      interval_secs = healthCheck.intervalSecs;
    }
    // optionalAttrs (healthCheck.timeoutSecs != null) {
      timeout_secs = healthCheck.timeoutSecs;
    }
    // optionalAttrs (healthCheck.startupGraceSecs != null) {
      startup_grace_secs = healthCheck.startupGraceSecs;
    };

  mkPlacementPolicySpec = placement:
    {
      roles = placement.roles;
      pools = placement.pools;
      node_classes = placement.nodeClasses;
      match_labels = placement.matchLabels;
      max_instances_per_node = placement.maxInstancesPerNode;
    }
    // optionalAttrs (placement.spreadByLabel != null) {
      spread_by_label = placement.spreadByLabel;
    };

  mkRolloutStrategySpec = rollout: {
    max_unavailable = rollout.maxUnavailable;
    max_surge = rollout.maxSurge;
  };

  mkServiceScheduleSpec = schedule:
    {
      mode = schedule.mode;
      replicas = schedule.replicas;
      placement = mkPlacementPolicySpec schedule.placement;
      rollout = mkRolloutStrategySpec schedule.rollout;
    }
    // optionalAttrs (schedule.instancePort != null) {
      instance_port = schedule.instancePort;
    }
    // optionalAttrs (schedule.meshPort != null) {
      mesh_port = schedule.meshPort;
    }
    // optionalAttrs (schedule.process != null) {
      process = mkProcessSpec schedule.process;
    }
    // optionalAttrs (schedule.container != null) {
      container = mkContainerSpec schedule.container;
    }
    // optionalAttrs (schedule.healthCheck != null) {
      health_check = mkHealthCheckSpec schedule.healthCheck;
    };

  mkDnsPublicationSpec = dns:
    {
      zone = dns.zone;
      ttl = dns.ttl;
      mode = dns.mode;
    }
    // optionalAttrs (dns.name != null) {
      name = dns.name;
    };

  mkLoadBalancerPublicationSpec = loadBalancer:
    optionalAttrs (loadBalancer.orgId != null)
      {
        org_id = loadBalancer.orgId;
      }
    // optionalAttrs (loadBalancer.projectId != null) {
      project_id = loadBalancer.projectId;
    }
    // optionalAttrs (loadBalancer.name != null) {
      name = loadBalancer.name;
    }
    // optionalAttrs (loadBalancer.listenerPort != null) {
      listener_port = loadBalancer.listenerPort;
    }
    // optionalAttrs (loadBalancer.protocol != null) {
      protocol = loadBalancer.protocol;
    }
    // optionalAttrs (loadBalancer.poolProtocol != null) {
      pool_protocol = loadBalancer.poolProtocol;
    };

  mkServicePublicationSpec = publish:
    optionalAttrs (publish.orgId != null)
      {
        org_id = publish.orgId;
      }
    // optionalAttrs (publish.projectId != null) {
      project_id = publish.projectId;
    }
    // optionalAttrs (publish.dns != null) {
      dns = mkDnsPublicationSpec publish.dns;
    }
    // optionalAttrs (publish.loadBalancer != null) {
      load_balancer = mkLoadBalancerPublicationSpec publish.loadBalancer;
    };

  mkDeployerServiceSpec = name: service:
    {
      inherit name;
    }
    // optionalAttrs (service.ports != null && mkServicePorts service.ports != { }) {
      ports = mkServicePorts service.ports;
    }
    // optionalAttrs (service.protocol != null) {
      protocol = service.protocol;
    }
    // optionalAttrs (service.mtlsRequired != null) {
      mtls_required = service.mtlsRequired;
    }
    // optionalAttrs (service.meshMode != null) {
      mesh_mode = service.meshMode;
    }
    // optionalAttrs (service.schedule != null) {
      schedule = mkServiceScheduleSpec service.schedule;
    }
    // optionalAttrs (service.publish != null) {
      publish = mkServicePublicationSpec service.publish;
    };

  mkDeployerMtlsPolicySpec = name: policy:
    {
      policy_id = name;
      source_service = policy.sourceService;
      target_service = policy.targetService;
    }
    // optionalAttrs (policy.environment != null) {
      environment = policy.environment;
    }
    // optionalAttrs (policy.mtlsRequired != null) {
      mtls_required = policy.mtlsRequired;
    }
    // optionalAttrs (policy.mode != null) {
      mode = policy.mode;
    };

  resolveBootstrapNodeName = cluster: bootstrapNodeName:
    let
      controlPlaneNodes =
        filter (n: (cluster.nodes.${n}.role or "worker") == "control-plane")
          (attrNames cluster.nodes);
    in
    if bootstrapNodeName != null then
      bootstrapNodeName
    else if cluster ? bootstrapNode && cluster.bootstrapNode != null then
      cluster.bootstrapNode
    else if cluster ? bootstrap && cluster.bootstrap ? initialPeers && cluster.bootstrap.initialPeers != [ ] then
      head cluster.bootstrap.initialPeers
    else
      head controlPlaneNodes;

  mkClusterConfig =
    { cluster
    , hostname
    , bootstrapNodeName ? null
    ,
    }:
    let
      node = cluster.nodes.${hostname} or (throw "Node ${hostname} not found in cluster configuration");

      controlPlaneNodes =
        filter (n: (cluster.nodes.${n}.role or "worker") == "control-plane")
          (attrNames cluster.nodes);

      resolvedBootstrapNodeName = resolveBootstrapNodeName cluster bootstrapNodeName;

      bootstrapNode = cluster.nodes.${resolvedBootstrapNodeName}
        or (throw "Bootstrap node ${resolvedBootstrapNodeName} not found in cluster configuration");

      initialPeers = map
        (nodeName: {
          id = nodeName;
          addr = "${cluster.nodes.${nodeName}.ip}:${toString cluster.nodes.${nodeName}.raftPort}";
        })
        controlPlaneNodes;

      flaredbPeers = map
        (nodeName:
          "${cluster.nodes.${nodeName}.ip}:${toString (cluster.nodes.${nodeName}.apiPort + 100)}"
        )
        controlPlaneNodes;

      chainfireLeaderUrl = "http://${bootstrapNode.ip}:8081";
      flaredbLeaderUrl = "http://${bootstrapNode.ip}:8082";
    in
    {
      node_id = hostname;
      node_role = node.role;
      bootstrap = hostname == resolvedBootstrapNodeName;
      cluster_name = cluster.name;
      leader_url = chainfireLeaderUrl;
      chainfire_leader_url = chainfireLeaderUrl;
      flaredb_leader_url = flaredbLeaderUrl;
      raft_addr = "${node.ip}:${toString node.raftPort}";
      initial_peers = initialPeers;
      flaredb_peers = flaredbPeers;
      services = node.services;
      metadata = node.metadata;
    } // optionalAttrs (cluster ? bgp && cluster.bgp ? asn) {
      bgp_asn = cluster.bgp.asn;
    };

  mkDeployerClusterState = cluster:
    let
      deployer = cluster.deployer or { };
      clusterId =
        if deployer ? clusterId && deployer.clusterId != null then
          deployer.clusterId
        else
          cluster.name;
      nodeClasses = deployer.nodeClasses or { };
      pools = deployer.pools or { };
      enrollmentRules = deployer.enrollmentRules or { };
      hostDeployments = deployer.hostDeployments or { };
      services = deployer.services or { };
      mtlsPolicies = deployer.mtlsPolicies or { };
    in
    {
      cluster = {
        cluster_id = clusterId;
      } // optionalAttrs (deployer ? environment && deployer.environment != null) {
        environment = deployer.environment;
      };
      nodes = map (nodeName: mkDeployerNodeSpec nodeName cluster.nodes.${nodeName}) (attrNames cluster.nodes);
      node_classes = map (name: mkDeployerNodeClassSpec name nodeClasses.${name}) (attrNames nodeClasses);
      pools = map (name: mkDeployerPoolSpec name pools.${name}) (attrNames pools);
      enrollment_rules = map (name: mkDeployerEnrollmentRuleSpec name enrollmentRules.${name}) (attrNames enrollmentRules);
      host_deployments = map (name: mkDeployerHostDeploymentSpec name hostDeployments.${name}) (attrNames hostDeployments);
      services = map (name: mkDeployerServiceSpec name services.${name}) (attrNames services);
      instances = [ ];
      mtls_policies = map (name: mkDeployerMtlsPolicySpec name mtlsPolicies.${name}) (attrNames mtlsPolicies);
    };
in
{
  inherit
    mkInstallPlanType
    mkDesiredSystemType
    mkHostDeploymentSelectorType
    mkHostDeploymentType
    mkServicePortsType
    mkProcessType
    mkContainerPortType
    mkContainerVolumeType
    mkContainerType
    mkHealthCheckType
    mkPlacementPolicyType
    mkRolloutStrategyType
    mkServiceScheduleType
    mkDnsPublicationType
    mkLoadBalancerPublicationType
    mkServicePublicationType
    mkServiceType
    mkMtlsPolicyType
    mkNodeType
    mkNodeClassType
    mkNodePoolType
    mkEnrollmentRuleType
    resolveBootstrapNodeName
    mkClusterConfig
    mkDeployerClusterState;
}
