// Copyright 2020-2026 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package buf.alpha.registry.v1alpha1;

import "buf/alpha/registry/v1alpha1/doc.proto";
import "buf/alpha/registry/v1alpha1/plugin_curation.proto";
import "buf/alpha/registry/v1alpha1/repository.proto";
import "buf/alpha/registry/v1alpha1/repository_commit.proto";
import "buf/alpha/registry/v1alpha1/repository_tag.proto";
import "buf/alpha/registry/v1alpha1/verification_status.proto";
import "google/protobuf/timestamp.proto";

enum SearchFilter {
  reserved 4, 5;
  reserved "SEARCH_FILTER_PLUGIN", "SEARCH_FILTER_TEMPLATE";

  SEARCH_FILTER_UNSPECIFIED = 0;
  SEARCH_FILTER_USER = 1;
  SEARCH_FILTER_ORGANIZATION = 2;
  SEARCH_FILTER_REPOSITORY = 3;
  SEARCH_FILTER_TEAM = 6;
  SEARCH_FILTER_CURATED_PLUGIN = 7;
  SEARCH_FILTER_MODULE_ELEMENT = 8;
  SEARCH_FILTER_MODULE_FILE = 9;
}

enum OrderBy {
  ORDER_BY_UNSPECIFIED = 0;
  ORDER_BY_CREATE_TIME = 1;
  ORDER_BY_UPDATE_TIME = 2;
  ORDER_BY_NAME = 3;
}

// SearchModuleElementType is the protobuf element type of a fully qualified name in a module element search result.
// This is a subset of types in https://protobuf.com/docs/language-spec#named-elements that are exposing in the search.
enum SearchModuleElementType {
  SEARCH_MODULE_ELEMENT_TYPE_UNSPECIFIED = 0;
  SEARCH_MODULE_ELEMENT_TYPE_SERVICE = 1;
  SEARCH_MODULE_ELEMENT_TYPE_METHOD = 2;
  SEARCH_MODULE_ELEMENT_TYPE_MESSAGE = 3;
  SEARCH_MODULE_ELEMENT_TYPE_ENUM = 4;
}

message RepositorySearchResult {
  string id = 1;
  string name = 2;
  // The name of the user or organization
  // who is the owner of this repository.
  string owner = 3;
  // The visibility of the repository.
  Visibility visibility = 4;
  bool deprecated = 5;
  // The SPDX license ID of the latest main commit in the repository.
  string latest_spdx_license_id = 6;
  // The verification status of the owner of the repository.
  VerificationStatus owner_verification_status = 7;
  // The user configurable URL in the description of the repository.
  string url = 8;
  // The commit time of the latest main commit in the repository.
  google.protobuf.Timestamp latest_commit_time = 9;
}

message OrganizationSearchResult {
  string id = 1;
  string name = 2;
  google.protobuf.Timestamp create_time = 3;
}

message UserSearchResult {
  string id = 1;
  string username = 2;
  bool deactivated = 3;
  google.protobuf.Timestamp create_time = 4;
}

message TeamSearchResult {
  string id = 1;
  string name = 2;
  string organization_name = 3;
}

message CuratedPluginSearchResult {
  string id = 1;
  string name = 2;
  // The name of the user or organization
  // who is the owner of this plugin.
  string owner = 3;
  bool deprecated = 4;
  // The description of the plugin and it's functionality.
  string description = 5;
  // The registry type of the plugin.
  PluginRegistryType registry_type = 6;
  // The output languages supported by the plugin.
  repeated PluginLanguage output_languages = 7;
  // The plugins creation timestamp.
  google.protobuf.Timestamp create_time = 8;
}

message ModuleElementSearchResult {
  string repository_id = 1;
  string repository_owner = 2;
  string repository_name = 3;
  string proto_file_path = 4;
  string fully_qualified_name = 5;
  string package_name = 6;
  SearchModuleElementType search_module_element_type = 7;
}

message ModuleFileSearchResult {
  string repository_id = 1;
  string repository_owner = 2;
  string repository_name = 3;
  string proto_file_path = 4;
}

message SearchResult {
  reserved 5, 6;
  reserved "plugin", "template";

  oneof item {
    RepositorySearchResult repository = 1;
    OrganizationSearchResult organization = 2;
    UserSearchResult user = 3;
    TeamSearchResult team = 4;
    CuratedPluginSearchResult curated_plugin = 7;
    ModuleElementSearchResult module_element = 8;
    ModuleFileSearchResult module_file = 9;
  }
}

enum SearchModuleContentFilter {
  SEARCH_MODULE_CONTENT_FILTER_UNSPECIFIED = 0;
  // SEARCH_MODULE_CONTENT_FILTER_ELEMENT is the filter for elements, e.g. messages, services, and methods.
  SEARCH_MODULE_CONTENT_FILTER_ELEMENT = 1;
  // SEARCH_MODULE_CONTENT_FILTER_FILE is the filter for files.
  SEARCH_MODULE_CONTENT_FILTER_FILE = 2;
}

message ElementSearchResult {
  string repository_id = 1;
  string repository_owner = 2;
  string repository_name = 3;
  string proto_file_path = 4;
  string fully_qualified_name = 5;
  oneof document {
    Service service = 6;
    Method method = 7;
    Enum enum = 8;
    Message message = 9;
    FileExtension file_extension = 10;
  }
}

message FileSearchResult {
  string repository_id = 1;
  string repository_owner = 2;
  string repository_name = 3;
  string proto_file_path = 4;
  bytes content = 5;
}

message SearchModuleContentResult {
  oneof item {
    ElementSearchResult element = 1;
    FileSearchResult file = 2;
  }
}

// SearchService is the search service.
service SearchService {
  // Search searches the BSR.
  rpc Search(SearchRequest) returns (SearchResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // SearchTag searches for tags in a repository
  rpc SearchTag(SearchTagRequest) returns (SearchTagResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // SearchDraft searches for drafts in a repository
  rpc SearchDraft(SearchDraftRequest) returns (SearchDraftResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
  // SearchModuleContent searches for module contents on the BSR.
  rpc SearchModuleContent(SearchModuleContentRequest) returns (SearchModuleContentResponse) {
    option idempotency_level = NO_SIDE_EFFECTS;
  }
}

message SearchRequest {
  // The search string.
  string query = 1;
  uint32 page_size = 2;
  // The first page is returned if this is 0.
  uint32 page_token = 3;
  // Empty list means show all. Supplying one or more enums will
  // limit the search to only the requested resources.
  // Supplying all possible enums is equivalent to empty list of filters.
  repeated SearchFilter filters = 4;
}

message SearchResponse {
  repeated SearchResult search_results = 1;
  // There are no more pages if this is 0.
  uint32 next_page_token = 2;
}

message SearchTagRequest {
  // The owner of the repository.
  string repository_owner = 1;
  // The name of the repository.
  string repository_name = 2;
  // The search string.
  string query = 3;
  uint32 page_size = 4;
  // The first page is returned if this is empty.
  string page_token = 5;
  // The field to order results by.
  OrderBy order_by = 6;
  // Reverse orders results in descending order.
  bool reverse = 7;
}

message SearchTagResponse {
  repeated RepositoryTag repository_tags = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message SearchDraftRequest {
  // The owner of the repository.
  string repository_owner = 1;
  // The name of the repository.
  string repository_name = 2;
  // The search string.
  string query = 3;
  uint32 page_size = 4;
  // The first page is returned if this is empty.
  string page_token = 5;
  // The field to order results by.
  OrderBy order_by = 6;
  // Reverse orders results in descending order.
  bool reverse = 7;
}

message SearchDraftResponse {
  repeated RepositoryCommit repository_commits = 1;
  // There are no more pages if this is empty.
  string next_page_token = 2;
}

message SearchModuleContentRequest {
  // The search string.
  string query = 1;
  uint32 page_size = 2;
  // The first page is returned if this is 0.
  uint32 page_token = 3;
  // Empty list means show all. Supplying one or more enums will
  // limit the search to only the requested resources.
  // Supplying all possible enums is equivalent to empty list of filters.
  repeated SearchModuleContentFilter filters = 4;
  // Optional, if provided the search results will be limited to the provided repository.
  string repository_full_name = 5;
  // Optional, if provided the search results will be limited to the provided owner,
  // ignored if repository_full_name is provided.
  string repository_owner = 6;
}

message SearchModuleContentResponse {
  repeated SearchModuleContentResult search_results = 1;
  // There are no more pages if this is 0.
  uint32 next_page_token = 2;
}
