# Infrastructure - Systemd Service Unit Schema
# Defines type-safe systemd service configuration
# Validates resource limits, dependencies, and restart policies

{
  # Unit section configuration
  UnitSection = {
    description | String,
    after | Array String | doc "Order dependencies" | default = [],
    before | Array String | doc "Reverse order dependencies" | default = [],
    requires | Array String | doc "Hard dependencies" | default = [],
    wants | Array String | doc "Soft dependencies" | default = [],
  },

  # Service resource limits
  ResourceLimits = {
    cpu_quota | String | optional,
    cpu_shares | Number | optional,
    memory_limit | String | optional,
    memory_high | String | optional,
  },

  # Service restart policy
  RestartPolicy = {
    restart | [| 'no, 'always, 'on_failure, 'on_abnormal, 'on_watchdog, 'on_abort, 'always |]
      | default = 'on_failure',
    restart_sec | String | doc "Restart delay" | default = "100ms",
    max_restarts | Number | optional,
  },

  # Service execution configuration
  ExecConfig = {
    exec_start | String,
    exec_stop | String | optional,
    exec_reload | String | optional,
    type | [| 'simple, 'exec, 'forking, 'oneshot, 'dbus, 'notify, 'idle |]
      | default = 'simple',
  },

  # Service section configuration
  ServiceSection = {
    exec_config | ExecConfig,
    resource_limits | ResourceLimits | default = {},
    restart_policy | RestartPolicy | default = {
      restart = 'on_failure',
      restart_sec = "100ms",
    },
    working_directory | String | optional,
    user | String | optional,
    group | String | optional,
    environment | Array String | doc "Environment variables" | default = [],
    environment_files | Array String | doc "Environment files to load" | default = [],
    timeout_start_sec | String | default = "90s",
    timeout_stop_sec | String | default = "90s",
    standard_output | [| 'journal, 'syslog, 'kmsg, 'null |] | default = 'journal',
    standard_error | [| 'journal, 'syslog, 'kmsg, 'null |] | default = 'journal',
  },

  # Install section configuration
  InstallSection = {
    wanted_by | Array String | doc "Install target" | default = ["multi-user.target"],
    required_by | Array String | doc "Required by target" | default = [],
    also | Array String | doc "Also install units" | default = [],
  },

  # Complete systemd service unit
  ServiceUnit = {
    unit | UnitSection,
    service | ServiceSection,
    install | InstallSection,
  },

  # Service unit builder function
  createService = fun name description exec_start =>
    {
      unit = {
        description = description,
        after = ["docker.service", "network-online.target"],
        before = [],
        requires = ["docker.service"],
        wants = [],
      },
      service = {
        exec_config = {
          exec_start = exec_start,
          type = 'forking',
        },
        resource_limits = {},
        restart_policy = {
          restart = 'unless_stopped',
          restart_sec = "5s",
        },
        timeout_start_sec = "90s",
        timeout_stop_sec = "90s",
        standard_output = 'journal',
        standard_error = 'journal',
      },
      install = {
        wanted_by = ["multi-user.target"],
      },
    },

  # Orchestrator service preset
  orchestratorServicePreset = {
    unit = {
      description = "Provisioning Platform Orchestrator",
      after = ["docker.service", "network-online.target"],
      requires = ["docker.service"],
      wants = ["kms.service"],
    },
    service = {
      exec_config = {
        exec_start = "/usr/bin/docker run --rm --name provisioning-orchestrator --net provisioning-net -p 8080:8080 -e PROVISIONING_MODE=solo -e ORCHESTRATOR_KMS_URL=http://kms:9998 provisioning/orchestrator:latest",
        exec_stop = "/usr/bin/docker stop provisioning-orchestrator",
        type = 'simple',
      },
      resource_limits = {
        cpu_quota = "200%",
        memory_limit = "1G",
      },
      restart_policy = {
        restart = 'unless_stopped',
        restart_sec = "5s",
      },
      user = "provisioning",
      group = "provisioning",
    },
    install = {
      wanted_by = ["multi-user.target"],
    },
  },

  # Control Center service preset
  controlCenterServicePreset = {
    unit = {
      description = "Provisioning Platform Control Center",
      after = ["docker.service", "orchestrator.service"],
      requires = ["docker.service"],
      wants = [],
    },
    service = {
      exec_config = {
        exec_start = "/usr/bin/docker run --rm --name provisioning-control-center --net provisioning-net -p 8081:8081 -e PROVISIONING_MODE=solo -e CONTROL_CENTER_ORCHESTRATOR_URL=http://orchestrator:8080 provisioning/control-center:latest",
        exec_stop = "/usr/bin/docker stop provisioning-control-center",
        type = 'simple',
      },
      resource_limits = {
        cpu_quota = "100%",
        memory_limit = "512M",
      },
      restart_policy = {
        restart = 'unless_stopped',
        restart_sec = "5s",
      },
      user = "provisioning",
      group = "provisioning",
    },
    install = {
      wanted_by = ["multi-user.target"],
    },
  },

  # KMS service preset (required for all modes)
  kmsServicePreset = {
    unit = {
      description = "Cosmian KMS - Key Management System",
      after = ["docker.service"],
      requires = ["docker.service"],
    },
    service = {
      exec_config = {
        exec_start = "/usr/bin/docker run --rm --name provisioning-kms --net provisioning-net -p 9998:9998 -v kms-data:/data -e KMS_DATABASE_PATH=/data/kms.db -e KMS_AUTH_METHOD=none ghcr.io/cosmian/kms:latest",
        exec_stop = "/usr/bin/docker stop provisioning-kms",
        type = 'simple',
      },
      resource_limits = {
        cpu_quota = "100%",
        memory_limit = "512M",
      },
      restart_policy = {
        restart = 'unless_stopped',
        restart_sec = "5s",
      },
      user = "provisioning",
      group = "provisioning",
      timeout_start_sec = "120s",
    },
    install = {
      wanted_by = ["multi-user.target"],
    },
  },

  # Solo mode all services
  soloModeServices = {
    orchestrator = orchestratorServicePreset,
    control_center = controlCenterServicePreset,
    kms = kmsServicePreset,
  },

  # Enterprise mode services (with replicas)
  enterpriseModeServices = {
    orchestrator_1 = orchestratorServicePreset & {
      unit.description = "Provisioning Platform Orchestrator (Replica 1)",
      service.resource_limits.cpu_quota = "400%",
      service.resource_limits.memory_limit = "2G",
    },
    orchestrator_2 = orchestratorServicePreset & {
      unit.description = "Provisioning Platform Orchestrator (Replica 2)",
      unit.after = ["orchestrator_1.service"],
      service.resource_limits.cpu_quota = "400%",
      service.resource_limits.memory_limit = "2G",
    },
    orchestrator_3 = orchestratorServicePreset & {
      unit.description = "Provisioning Platform Orchestrator (Replica 3)",
      unit.after = ["orchestrator_2.service"],
      service.resource_limits.cpu_quota = "400%",
      service.resource_limits.memory_limit = "2G",
    },
    control_center_1 = controlCenterServicePreset & {
      unit.description = "Provisioning Platform Control Center (Replica 1)",
      service.resource_limits.cpu_quota = "200%",
      service.resource_limits.memory_limit = "1G",
    },
    control_center_2 = controlCenterServicePreset & {
      unit.description = "Provisioning Platform Control Center (Replica 2)",
      unit.after = ["control_center_1.service"],
      service.resource_limits.cpu_quota = "200%",
      service.resource_limits.memory_limit = "1G",
    },
    kms = kmsServicePreset & {
      service.resource_limits.cpu_quota = "200%",
      service.resource_limits.memory_limit = "1G",
    },
  },
}
