// This proto file was generated from unified-search.yml.
// Care should be taken while both files exist to maintain backwards compatibility with the Conjure generated code.

syntax = "proto3";

package nominal.metadata.v1;

import "buf/validate/validate.proto";
import "google/api/annotations.proto";
import "nominal/protos/conjure/v1/compat.proto";
import "nominal/protos/gen/v1/alias.proto";
import "nominal/protos/gen/v1/error.proto";
import "nominal/protos/types/types.proto";

option java_multiple_files = true;
option java_package = "io.nominal.metadata.v1";

message FindSimilarLabelMatchesRequest {
  // If omitted, all resource types are included.
  repeated ResourceType resource_types = 1;

  // If omitted, results will come from all workspaces the user belongs to.
  repeated string workspaces = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];

  repeated string labels = 3 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];
}

message FindSimilarLabelMatchesResponse {
  map<string, FindSimilarLabelMatchesResponseMatchesWrapper> matches = 1 [
    (nominal.gen.v1.alias) = {key_java_name: "io.nominal.api.Label"},
    (nominal.conjure.v1.conjure_field_compat) = {map_value_wrapper: true}
  ];

  message FindSimilarLabelMatchesResponseMatchesWrapper {
    repeated MatchCount value = 1;
  }
}

message FindSimilarPropertyKeyMatchesRequest {
  // If omitted, all resource types are included.
  repeated ResourceType resource_types = 1;

  // If omitted, results will come from all workspaces the user belongs to.
  repeated string workspaces = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];

  repeated string property_keys = 3 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyName"}];
}

message FindSimilarPropertyKeyMatchesResponse {
  map<string, FindSimilarPropertyKeyMatchesResponseKeyMatchesWrapper> key_matches = 1 [
    (nominal.gen.v1.alias) = {key_java_name: "io.nominal.api.PropertyName"},
    (nominal.conjure.v1.conjure_field_compat) = {map_value_wrapper: true}
  ];

  message FindSimilarPropertyKeyMatchesResponseKeyMatchesWrapper {
    repeated MatchCount value = 1;
  }
}

message GetMetadataUsageCountRequest {
  MetadataUsageQuery query = 1;

  // If omitted, all resource types are included.
  repeated ResourceType resource_types = 2;

  // If omitted, results will come from all workspaces the user belongs to.
  repeated string workspaces = 3 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];
}

message GetMetadataUsageCountResponse {
  int32 count = 1;
}

message LabelWithCount {
  string label = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];

  int32 document_count = 2;
}

message ListPropertiesAndLabelsRequest {
  // If omitted, all resource types are included.
  repeated ResourceType resource_types = 1;

  // If omitted, results will come from all workspaces the user belongs to.
  repeated string workspaces = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];
}

message ListPropertiesAndLabelsResponse {
  map<string, ListPropertiesAndLabelsResponsePropertiesWrapper> properties = 1 [
    (nominal.gen.v1.alias) = {key_java_name: "io.nominal.api.PropertyName"},
    (nominal.conjure.v1.conjure_field_compat) = {map_value_wrapper: true}
  ];

  repeated string labels = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];

  message ListPropertiesAndLabelsResponsePropertiesWrapper {
    repeated string value = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyValue"}];
  }
}

message MatchCount {
  string value = 1;

  int32 document_count = 2;
}

// buf:lint:ignore ENUM_VALUE_PREFIX
enum MetadataSortField {
  METADATA_SORT_FIELD_UNSPECIFIED = 0;
  ALPHABETICAL = 1;
  USAGE_COUNT = 2;
  PROPERTY_VALUE_COUNT = 3;
}

// Specifies what metadata to count usage for. Exactly one of: a label,
// a property name (counts all resources with any value for that key),
// or a full property key+value pair.
message MetadataUsageQuery {
  option (nominal.conjure.v1.conjure_compat) = {union_message: true};

  // Specifies what metadata to count usage for. Exactly one of: a label,
  // a property name (counts all resources with any value for that key),
  // or a full property key+value pair.
  oneof metadata_usage_query {
    option (buf.validate.oneof) = {required: true};

    string label = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];
    string property_name = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyName"}];
    nominal.types.Property property = 3;
  }
}

message PropertyKeyWithCount {
  string property_key = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyName"}];

  int32 document_count = 2;

  int32 value_count = 3;
}

message PropertyValueWithCount {
  string property_value = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyValue"}];

  int32 document_count = 2;
}

// buf:lint:ignore ENUM_VALUE_PREFIX
enum ResourceType {
  RESOURCE_TYPE_UNSPECIFIED = 0;
  RUN = 1;
  VIDEO = 2;
  ASSET = 3;
  EVENT = 4;
  DATASET = 5;
  MODULE = 6;
  PROCEDURE_EXECUTION = 7;
  PROCEDURE = 8;
  SAVED_VIEW = 9;
}

message SearchLabelsResponse {
  repeated LabelWithCount labels = 1;

  optional string next_page_token = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];
}

message SearchMetadataRequest {
  // If omitted, all resource types are included.
  repeated ResourceType resource_types = 1;

  // If omitted, results will come from all workspaces the user belongs to.
  repeated string workspaces = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];

  // Case-insensitive substring filter.
  optional string search_text = 3;

  // Maximum number of items per page. Defaults to 1000 if not specified.
  optional int32 page_size = 4;

  // Token for fetching the next page of results.
  optional string page_token = 5 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];

  MetadataSortField sort_by = 6;

  // If true, sort in descending order. Defaults to false.
  optional bool descending = 7;
}

message SearchPropertyKeysResponse {
  repeated PropertyKeyWithCount property_keys = 1;

  optional string next_page_token = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];
}

message SearchPropertyValuesRequest {
  SearchMetadataRequest search = 1;

  string property_key = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.PropertyName"}];
}

message SearchPropertyValuesResponse {
  repeated PropertyValueWithCount property_values = 1;

  optional string next_page_token = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];
}

// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
enum MetadataError {
  METADATA_ERROR_INVALID_METADATA_REQUEST = 0 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "InvalidMetadataRequest"
  }];
}

// The Resource Metadata Service provides common metadata about resources.
service ResourceMetadataService {
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Returns all existing properties (key value pairs) and labels, which can be used to organize resources
  // such as runs and videos.
  //
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc ListPropertiesAndLabels(ListPropertiesAndLabelsRequest) returns (ListPropertiesAndLabelsResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/list-properties-labels"
      body: "*"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Returns the count of resources that use a given label or property. The query can
  // match by label, property name (key only), or a full property key+value pair.
  // Counts are scoped to the caller's accessible workspaces unless specific workspaces
  // are provided.
  //
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc GetMetadataUsageCount(GetMetadataUsageCountRequest) returns (GetMetadataUsageCountResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/usage-count"
      body: "*"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Given a set of labels, finds similar labels across the specified workspaces and resource types.
  // Includes document count. Useful for detecting unintentional duplicate labels.
  //
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc FindSimilarLabelMatches(FindSimilarLabelMatchesRequest) returns (FindSimilarLabelMatchesResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/label/find-similar"
      body: "*"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Given a set of property keys, finds similar property keys across the specified workspaces and resource types.
  // Includes document count. Useful for detecting unintentional duplicate property keys.
  //
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc FindSimilarPropertyKeyMatches(FindSimilarPropertyKeyMatchesRequest) returns (FindSimilarPropertyKeyMatchesResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/property/find-similar"
      body: "*"
    };
  }
  // Returns a paginated list of labels with document usage counts, filterable by
  // resource type, workspace, and search text.
  //
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc SearchLabels(SearchMetadataRequest) returns (SearchLabelsResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/search-labels"
      body: "*"
    };
  }
  // Returns a paginated list of property keys with document usage counts, filterable
  // by resource type, workspace, and search text.
  //
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc SearchPropertyKeys(SearchMetadataRequest) returns (SearchPropertyKeysResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/search-property-keys"
      body: "*"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Returns a paginated list of property values for a given property key with document
  // usage counts, filterable by resource type, workspace, and search text.
  //
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  rpc SearchPropertyValues(SearchPropertyValuesRequest) returns (SearchPropertyValuesResponse) {
    option (google.api.http) = {
      post: "/scout/v1/metadata/search-property-values"
      body: "*"
    };
  }
}
