syntax = "proto3";

package laborato.mesh;

import "Proto/common/node.proto";
import "Proto/common/policy.proto";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

// SYSTEM HEARTBEAT
message HeartbeatRequest {
    string nodeId = 1;
    google.protobuf.Timestamp timestamp = 2;
}

message HeartbeatResponse {
    google.protobuf.Timestamp serverTime = 1;
}

message NodeInfoRequest {
    string nodeId = 1; // optional
}

message NodeInfoResponse {
    laborato.common.node.NodeFullInfo info = 1;
}

// POLICY DEFINITIONS
enum PolicyScope {
    POLICY_SCOPE_NONE = 0;
    POLICY_SCOPE_USER = 1;
    POLICY_SCOPE_MACHINE = 2;
    POLICY_SCOPE_BOTH = 3;
}

message PolicyElement {
    string id_name = 1;
    string type = 2; // text, checkbox, list, combobox, etc.
    string value_name = 3;
    int32 max_length = 4;
    bool required = 5;
    string client_extension = 6;
}

message PolicyDescriptor {
    string policy_hash = 1;
    string name = 2;
    PolicyScope scope = 3;
    string registry_key = 4;
    string value_name = 5;
    string enabled_value = 6;
    string disabled_value = 7;
    string supported_on_ref = 8;
    string parent_category = 9;
    repeated PolicyElement elements = 10;
    repeated string required_capabilities = 11;
    repeated string required_hardware = 12;
    repeated string admx_file_hashes = 13;
    int64 revision = 14; // мастерская ревизия политики
}

message AdmxFileDescriptor {
    string file_hash = 1;
    string file_name = 2;
    bytes content = 3; // опционально, может быть только хэш для проверки
    int64 revision = 4;
}

// POLICY STATE REPORT (AGENT -> MASTER)
message PolicyStateReportRequest {
    string agent_id = 1;
    int64 revision = 2;
    repeated PolicyStateItem items = 3;
    laborato.common.policy.PolicySelection selection = 4;
}

message PolicyStateItem {
    string policy_hash = 1;
    string user_sid = 2;
    repeated PolicyStateItem childs = 3;
    laborato.common.policy.PolicySelection selection = 4;
}

service MeshService {
    // Node information
    rpc SendNodeInfo(laborato.common.node.NodeFullInfo) returns (google.protobuf.Empty);
    rpc RequestNodeInfo(NodeInfoRequest) returns (NodeInfoResponse);
    rpc StreamNodeInfo(stream laborato.common.node.NodeFullInfo) returns (google.protobuf.Empty);

    // System heartbeat
    rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse);

    // Policy state reporting
    rpc ReportPolicyState(PolicyStateReportRequest) returns (google.protobuf.Empty);
}

// POLICY SYNCHRONIZATION
enum PolicySyncMode {
  SYNC_MODE_NONE = 0;
  SYNC_MODE_SNAPSHOT = 1;
  SYNC_MODE_DIFF = 2; // зарезервировано
}

message PolicySyncRequest {
  string agent_id = 1;
  int64 last_known_revision = 2;
}

message PolicySyncInit {
  PolicySyncMode mode = 1;
  int64 master_revision = 2;
  string sha256 = 3;
  int64 payload_size = 4;
}

message PolicySyncChunk {
  bytes data = 1;
  bool last = 2;
}

service PolicySyncService {
    // Sync policies and ADMX files (MASTER -> AGENT)
    rpc StartPolicySync(PolicySyncRequest) returns (PolicySyncInit);
    rpc StreamPolicyPayload(google.protobuf.Empty) returns (stream PolicySyncChunk);
}

// Stream policy assigment sync
service PolicyControlService {
    rpc PolicyControlStream(stream AgentMessage) returns (stream MasterMessage);
    rpc GetAssigments(AssigmentsRequestMessage) returns (AssigmentsResponse);
}

message AssigmentsRequestMessage {
  string agent_id = 1;
}

message AssigmentsResponse {
  string agent_id = 1;
  repeated ApplyPolicyCommand apply_commands = 2;
  repeated RemovePolicyCommand remove_commands = 3;
}

message AgentMessage {
  string agent_id = 1;

  oneof payload {
    laborato.common.node.NodeFullInfo hello = 2;
    PolicyStateReportRequest state_report = 3;
    HeartbeatRequest heartbeat = 4;
  }
}

message MasterMessage {
  oneof payload {
    ApplyPolicyCommand apply = 1;
    RemovePolicyCommand remove = 2;
    SyncRequired sync = 3;
  }
}

message ApplyPolicyCommand {
  string policy_hash = 1;
  int64 revision = 2;
  laborato.common.policy.PolicySelection selection = 3;
  oneof target {
    string user_sid = 4;
    bool machine_scope = 5;
  }
}

message RemovePolicyCommand {
  string policy_hash = 1;
  int64 revision = 2;
  oneof target {
    string user_sid = 3;
    bool machine_scope = 4;
  }
}

message SyncRequired {
  int64 master_revision = 1;
  optional string reason = 2; // optional: "master_restart", "agent_reconnect", "missed_events"
}