{ config, lib, pkgs, ... }:

let
  cfg = config.services.plasmavmc;
  localIamDeps = lib.optional (config.services.iam.enable or false) "iam.service";
  localIamHealthUrl =
    if config.services.iam.enable or false
    then "http://127.0.0.1:${toString config.services.iam.httpPort}/health"
    else null;
  remoteIamEndpoint =
    if !(config.services.iam.enable or false) && cfg.iamAddr != null
    then cfg.iamAddr
    else null;
  coronafsEnabled = lib.hasAttrByPath [ "services" "coronafs" "enable" ] config && config.services.coronafs.enable;
  coronafsDataDir =
    if coronafsEnabled && lib.hasAttrByPath [ "services" "coronafs" "dataDir" ] config
    then toString config.services.coronafs.dataDir
    else null;
  effectiveCoronafsControllerEndpoint =
    if cfg.coronafsControllerEndpoint != null then cfg.coronafsControllerEndpoint
    else if cfg.coronafsEndpoint != null then cfg.coronafsEndpoint
    else if coronafsEnabled then "http://127.0.0.1:${toString config.services.coronafs.port}"
    else null;
  effectiveCoronafsNodeEndpoint =
    if cfg.coronafsNodeEndpoint != null then cfg.coronafsNodeEndpoint
    else if coronafsEnabled then "http://127.0.0.1:${toString config.services.coronafs.port}"
    else if cfg.coronafsEndpoint != null then cfg.coronafsEndpoint
    else null;
  tomlFormat = pkgs.formats.toml { };
  plasmavmcConfigFile = tomlFormat.generate "plasmavmc.toml" {
    addr = "0.0.0.0:${toString cfg.port}";
    http_addr = "0.0.0.0:${toString cfg.httpPort}";
    log_level = "info";
    auth = {
      iam_server_addr =
        if cfg.iamAddr != null
        then cfg.iamAddr
        else "127.0.0.1:50080";
    };
  };
in
{
  options.services.plasmavmc = {
    enable = lib.mkEnableOption "plasmavmc service";

    mode = lib.mkOption {
      type = lib.types.enum [ "server" "agent" "all-in-one" ];
      default = "all-in-one";
      description = "PlasmaVMC operating mode: server (control-plane), agent (compute), or all-in-one";
    };

    port = lib.mkOption {
      type = lib.types.port;
      default = 50082;
      description = "Port for plasmavmc gRPC API";
    };

    httpPort = lib.mkOption {
      type = lib.types.port;
      default = 8084;
      description = "Port for plasmavmc HTTP REST API";
    };

    prismnetAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "PrismNET service endpoint address (host:port)";
      example = "10.0.0.1:50081";
    };

    iamAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "IAM service endpoint address (host:port)";
      example = "10.0.0.1:50080";
    };

    chainfireAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "ChainFire endpoint address (host:port) for cluster coordination only";
      example = "10.0.0.1:2379";
    };

    flaredbAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "FlareDB endpoint address (host:port) for metadata/user data";
      example = "10.0.0.1:2479";
    };

    controlPlaneAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "PlasmaVMC control-plane gRPC endpoint (host:port) for agent heartbeats.";
      example = "10.0.0.11:50082";
    };

    advertiseAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "Advertised PlasmaVMC gRPC endpoint for scheduler forwarding (host:port).";
      example = "10.0.0.21:50082";
    };

    lightningstorAddr = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "LightningStor gRPC endpoint (host:port) for VM image artifacts.";
      example = "10.0.0.11:50086";
    };

    coronafsEndpoint = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "Deprecated combined CoronaFS HTTP endpoint used to provision and export managed VM volumes.";
      example = "http://10.0.0.11:50088";
    };

    coronafsControllerEndpoint = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "CoronaFS controller HTTP endpoint used to provision and resize managed VM volumes. Comma-separated endpoints are allowed for client-side failover.";
      example = "http://10.0.0.11:50088";
    };

    coronafsNodeEndpoint = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "CoronaFS node-local HTTP endpoint used to resolve local paths and exports for attached VM volumes. Comma-separated endpoints are allowed for client-side failover.";
      example = "http://127.0.0.1:50088";
    };

    coronafsNodeLocalAttach = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = ''
        Enable writable VM attachment through node-local CoronaFS materialization.
        This requires services.plasmavmc.sharedLiveMigration = false because migrations use cold relocate plus flush-back.
      '';
    };

    experimentalCoronafsNodeLocalAttach = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = ''
        Deprecated alias for services.plasmavmc.coronafsNodeLocalAttach.
      '';
    };

    managedVolumeRoot = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/plasmavmc/managed-volumes";
      description = "Local root directory used for PlasmaVMC managed raw volumes.";
    };

    sharedLiveMigration = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = "Whether this node advertises shared-storage live migration capability.";
    };

    cephMonitors = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      description = "Optional Ceph monitor endpoints used to enable Ceph RBD volumes.";
      example = [ "10.0.0.31:6789" "10.0.0.32:6789" "10.0.0.33:6789" ];
    };

    cephClusterId = lib.mkOption {
      type = lib.types.str;
      default = "default";
      description = "Ceph cluster identifier expected by registered Ceph RBD volumes.";
    };

    cephUser = lib.mkOption {
      type = lib.types.str;
      default = "admin";
      description = "Ceph user passed to QEMU RBD attachments.";
    };

    cephSecret = lib.mkOption {
      type = lib.types.nullOr lib.types.str;
      default = null;
      description = "Optional Ceph secret used for QEMU RBD attachments.";
    };

    nodeId = lib.mkOption {
      type = lib.types.str;
      default = config.networking.hostName;
      description = "Node identifier used when running in agent/all-in-one mode.";
    };

    nodeName = lib.mkOption {
      type = lib.types.str;
      default = config.networking.hostName;
      description = "Node display name used in PlasmaVMC heartbeats.";
    };

    heartbeatIntervalSeconds = lib.mkOption {
      type = lib.types.int;
      default = 5;
      description = "Heartbeat interval for PlasmaVMC agents.";
    };

    dataDir = lib.mkOption {
      type = lib.types.path;
      default = "/var/lib/plasmavmc";
      description = "Data directory for plasmavmc";
    };

    settings = lib.mkOption {
      type = lib.types.attrs;
      default = {};
      description = "Additional configuration settings";
    };

    package = lib.mkOption {
      type = lib.types.package;
      default = pkgs.plasmavmc-server or (throw "plasmavmc-server package not found");
      description = "Package to use for plasmavmc";
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      {
        assertion = !((cfg.coronafsNodeLocalAttach || cfg.experimentalCoronafsNodeLocalAttach) && cfg.sharedLiveMigration);
        message = ''
          services.plasmavmc.coronafsNodeLocalAttach requires services.plasmavmc.sharedLiveMigration = false
          because writable node-local CoronaFS attachment uses cold relocate plus flush-back instead of shared-storage live migration.
        '';
      }
    ];

    warnings =
      lib.optional (cfg.coronafsEndpoint != null) ''
        services.plasmavmc.coronafsEndpoint is deprecated; use services.plasmavmc.coronafsControllerEndpoint and services.plasmavmc.coronafsNodeEndpoint.
      ''
      ++ lib.optional (cfg.experimentalCoronafsNodeLocalAttach) ''
        services.plasmavmc.experimentalCoronafsNodeLocalAttach is deprecated; use services.plasmavmc.coronafsNodeLocalAttach.
      '';

    # Create system user
    users.users.plasmavmc = {
      isSystemUser = true;
      group = "plasmavmc";
      description = "PlasmaVMC service user";
      home = cfg.dataDir;
      extraGroups = [ "kvm" ] ++ lib.optional coronafsEnabled "coronafs";
    };

    users.groups.plasmavmc = {};

    # Create systemd service
    systemd.services.plasmavmc = {
      description = "PlasmaVMC Virtual Machine Compute Service";
      wantedBy = [ "multi-user.target" ];
      after = [ "network-online.target" "prismnet.service" "flaredb.service" "chainfire.service" ] ++ localIamDeps;
      wants = [ "network-online.target" "prismnet.service" "flaredb.service" "chainfire.service" ] ++ localIamDeps;
      path = [ pkgs.qemu pkgs.coreutils pkgs.curl ];
      preStart =
        lib.optionalString (localIamHealthUrl != null) ''
          for _ in $(seq 1 90); do
            if curl -fsS ${lib.escapeShellArg localIamHealthUrl} >/dev/null 2>&1; then
              exit 0
            fi
            sleep 1
          done
          echo "plasmavmc: timed out waiting for local IAM health at ${localIamHealthUrl}" >&2
          exit 1
        ''
        + lib.optionalString (remoteIamEndpoint != null) ''
          endpoint=${lib.escapeShellArg remoteIamEndpoint}
          endpoint="''${endpoint#http://}"
          endpoint="''${endpoint#https://}"
          host="''${endpoint%:*}"
          port="''${endpoint##*:}"
          for _ in $(${pkgs.coreutils}/bin/seq 1 90); do
            if ${pkgs.coreutils}/bin/timeout 1 ${pkgs.bash}/bin/bash -lc "</dev/tcp/''${host}/''${port}" >/dev/null 2>&1; then
              exit 0
            fi
            sleep 1
          done
          echo "plasmavmc: timed out waiting for IAM gRPC at ''${host}:''${port}" >&2
          exit 1
        '';

      environment = lib.mkMerge [
        {
          PLASMAVMC_MODE = cfg.mode;
          PLASMAVMC_STORAGE_BACKEND = "flaredb";
          PLASMAVMC_FLAREDB_ENDPOINT = if cfg.flaredbAddr != null then cfg.flaredbAddr else "127.0.0.1:2479";
          PLASMAVMC_QEMU_PATH = "${pkgs.qemu}/bin/qemu-system-x86_64";
          PLASMAVMC_RUNTIME_DIR = "/run/libvirt/plasmavmc";
          PLASMAVMC_IMAGE_CACHE_DIR = "${toString cfg.dataDir}/images";
          PLASMAVMC_MANAGED_VOLUME_ROOT = toString cfg.managedVolumeRoot;
          PLASMAVMC_SHARED_LIVE_MIGRATION = lib.boolToString cfg.sharedLiveMigration;
        }
        (lib.mkIf (cfg.prismnetAddr != null) {
          PRISMNET_ENDPOINT = "http://${cfg.prismnetAddr}";
        })
        (lib.mkIf (cfg.chainfireAddr != null) {
          PLASMAVMC_CHAINFIRE_ENDPOINT = "http://${cfg.chainfireAddr}";
          PLASMAVMC_STATE_WATCHER = "1";
        })
        (lib.mkIf (cfg.lightningstorAddr != null) {
          PLASMAVMC_LIGHTNINGSTOR_ENDPOINT = cfg.lightningstorAddr;
        })
        (lib.mkIf (effectiveCoronafsControllerEndpoint != null) {
          PLASMAVMC_CORONAFS_CONTROLLER_ENDPOINT = effectiveCoronafsControllerEndpoint;
        })
        (lib.mkIf (effectiveCoronafsNodeEndpoint != null) {
          PLASMAVMC_CORONAFS_NODE_ENDPOINT = effectiveCoronafsNodeEndpoint;
        })
        (lib.mkIf (cfg.coronafsNodeLocalAttach || cfg.experimentalCoronafsNodeLocalAttach) {
          PLASMAVMC_CORONAFS_NODE_LOCAL_ATTACH = "1";
          PLASMAVMC_CORONAFS_ENABLE_EXPERIMENTAL_NODE_LOCAL_ATTACH = "1";
        })
        (lib.mkIf (cfg.coronafsEndpoint != null) {
          PLASMAVMC_CORONAFS_ENDPOINT = cfg.coronafsEndpoint;
        })
        (lib.mkIf (cfg.cephMonitors != [ ]) {
          PLASMAVMC_CEPH_MONITORS = lib.concatStringsSep "," cfg.cephMonitors;
          PLASMAVMC_CEPH_CLUSTER_ID = cfg.cephClusterId;
          PLASMAVMC_CEPH_USER = cfg.cephUser;
        })
        (lib.mkIf (cfg.cephSecret != null) {
          PLASMAVMC_CEPH_SECRET = cfg.cephSecret;
        })
        (lib.mkIf (cfg.mode != "server") {
          PLASMAVMC_NODE_ID = cfg.nodeId;
          PLASMAVMC_NODE_NAME = cfg.nodeName;
          PLASMAVMC_NODE_HEARTBEAT_INTERVAL_SECS = toString cfg.heartbeatIntervalSeconds;
        })
        (lib.mkIf (cfg.controlPlaneAddr != null) {
          PLASMAVMC_CONTROL_PLANE_ADDR = cfg.controlPlaneAddr;
        })
        (lib.mkIf (cfg.advertiseAddr != null) {
          PLASMAVMC_ENDPOINT_ADVERTISE = cfg.advertiseAddr;
        })
        (lib.mkIf (cfg.mode == "server") {
          PLASMAVMC_NODE_HEALTH_MONITOR_INTERVAL_SECS = "5";
          PLASMAVMC_NODE_HEARTBEAT_TIMEOUT_SECS = "30";
        })
      ];

      serviceConfig = {
        Type = "simple";
        User = "plasmavmc";
        Group = "plasmavmc";
        SupplementaryGroups = [ "kvm" ] ++ lib.optional coronafsEnabled "coronafs";
        Restart = "on-failure";
        RestartSec = "10s";

        # State directory management
        StateDirectory = "plasmavmc";
        StateDirectoryMode = "0750";
        RuntimeDirectory = "libvirt";
        RuntimeDirectoryMode = "0755";

        # Security hardening - relaxed for KVM access
        NoNewPrivileges = false;  # Needed for KVM
        PrivateTmp = true;
        ProtectSystem = "strict";
        ProtectHome = true;
        ReadWritePaths =
          [ cfg.dataDir "/run/libvirt" cfg.managedVolumeRoot ]
          ++ lib.optionals (coronafsDataDir != null) [ coronafsDataDir ];
        DeviceAllow = [ "/dev/kvm rw" ];

        # Start command
        ExecStart = "${cfg.package}/bin/plasmavmc-server --config ${plasmavmcConfigFile}";
      };
    };

    systemd.tmpfiles.rules = [
      "d ${builtins.dirOf (toString cfg.managedVolumeRoot)} 0755 plasmavmc plasmavmc -"
      "d ${toString cfg.managedVolumeRoot} 0750 plasmavmc plasmavmc -"
    ] ++ lib.optionals coronafsEnabled [
      "d ${toString cfg.dataDir}/images 2770 plasmavmc coronafs -"
    ];
  };
}
