// Copyright 2025 Google LLC
//
// 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 google.cloud.resourcemanager.v3;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";

option csharp_namespace = "Google.Cloud.ResourceManager.V3";
option go_package = "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb;resourcemanagerpb";
option java_multiple_files = true;
option java_outer_classname = "TagHoldsProto";
option java_package = "com.google.cloud.resourcemanager.v3";
option php_namespace = "Google\\Cloud\\ResourceManager\\V3";
option ruby_package = "Google::Cloud::ResourceManager::V3";

// Allow users to create and manage TagHolds for TagValues. TagHolds represent
// the use of a Tag Value that is not captured by TagBindings but
// should still block TagValue deletion (such as a reference in a policy
// condition). This service provides isolated failure domains by cloud location
// so that TagHolds can be managed in the same location as their usage.
service TagHolds {
  option (google.api.default_host) = "cloudresourcemanager.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform,"
      "https://www.googleapis.com/auth/cloud-platform.read-only";

  // Creates a TagHold. Returns ALREADY_EXISTS if a TagHold with the same
  // resource and origin exists under the same TagValue.
  rpc CreateTagHold(CreateTagHoldRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v3/{parent=tagValues/*}/tagHolds"
      body: "tag_hold"
    };
    option (google.api.method_signature) = "parent,tag_hold";
    option (google.longrunning.operation_info) = {
      response_type: "TagHold"
      metadata_type: "CreateTagHoldMetadata"
    };
  }

  // Deletes a TagHold.
  rpc DeleteTagHold(DeleteTagHoldRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v3/{name=tagValues/*/tagHolds/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "google.protobuf.Empty"
      metadata_type: "DeleteTagHoldMetadata"
    };
  }

  // Lists TagHolds under a TagValue.
  rpc ListTagHolds(ListTagHoldsRequest) returns (ListTagHoldsResponse) {
    option (google.api.http) = {
      get: "/v3/{parent=tagValues/*}/tagHolds"
    };
    option (google.api.method_signature) = "parent";
  }
}

// A TagHold represents the use of a TagValue that is not captured by
// TagBindings. If a TagValue has any TagHolds, deletion will be blocked.
// This resource is intended to be created in the same cloud location as the
// `holder`.
message TagHold {
  option (google.api.resource) = {
    type: "cloudresourcemanager.googleapis.com/TagHold"
    pattern: "tagValues/{tag_value}/tagHolds/{tag_hold}"
  };

  // Output only. The resource name of a TagHold. This is a String of the form:
  // `tagValues/{tag-value-id}/tagHolds/{tag-hold-id}`
  // (e.g. `tagValues/123/tagHolds/456`). This resource name is generated by
  // the server.
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The name of the resource where the TagValue is being used. Must
  // be less than 200 characters. E.g.
  // `//compute.googleapis.com/compute/projects/myproject/regions/us-east-1/instanceGroupManagers/instance-group`
  string holder = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. An optional string representing the origin of this request. This
  // field should include human-understandable information to distinguish
  // origins from each other. Must be less than 200 characters. E.g.
  // `migs-35678234`
  string origin = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A URL where an end user can learn more about removing this hold.
  // E.g.
  // `https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing`
  string help_link = 4 [(google.api.field_behavior) = OPTIONAL];

  // Output only. The time this TagHold was created.
  google.protobuf.Timestamp create_time = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The request message to create a TagHold.
message CreateTagHoldRequest {
  // Required. The resource name of the TagHold's parent TagValue. Must be of
  // the form: `tagValues/{tag-value-id}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "cloudresourcemanager.googleapis.com/TagHold"
    }
  ];

  // Required. The TagHold to be created.
  TagHold tag_hold = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. Set to true to perform the validations necessary for creating the
  // resource, but not actually perform the action.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Runtime operation information for creating a TagHold.
// (-- The metadata is currently empty, but may include information in the
// future. --)
message CreateTagHoldMetadata {}

// The request message to delete a TagHold.
message DeleteTagHoldRequest {
  // Required. The resource name of the TagHold to delete. Must be of the form:
  // `tagValues/{tag-value-id}/tagHolds/{tag-hold-id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/TagHold"
    }
  ];

  // Optional. Set to true to perform the validations necessary for deleting the
  // resource, but not actually perform the action.
  bool validate_only = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Runtime operation information for deleting a TagHold.
// (-- The metadata is currently empty, but may include information in the
// future. --)
message DeleteTagHoldMetadata {}

// The request message for listing the TagHolds under a TagValue.
message ListTagHoldsRequest {
  // Required. The resource name of the parent TagValue. Must be of the form:
  // `tagValues/{tag-value-id}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "cloudresourcemanager.googleapis.com/TagHold"
    }
  ];

  // Optional. The maximum number of TagHolds to return in the response. The
  // server allows a maximum of 300 TagHolds to return. If unspecified, the
  // server will use 100 as the default.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A pagination token returned from a previous call to
  // `ListTagHolds` that indicates where this listing should continue from.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Criteria used to select a subset of TagHolds parented by the
  // TagValue to return. This field follows the syntax defined by aip.dev/160;
  // the `holder` and `origin` fields are supported for filtering. Currently
  // only `AND` syntax is supported. Some example queries are:
  //
  //   * `holder =
  //     //compute.googleapis.com/compute/projects/myproject/regions/us-east-1/instanceGroupManagers/instance-group`
  //   * `origin = 35678234`
  //   * `holder =
  //     //compute.googleapis.com/compute/projects/myproject/regions/us-east-1/instanceGroupManagers/instance-group
  //     AND origin = 35678234`
  string filter = 4 [(google.api.field_behavior) = OPTIONAL];
}

// The ListTagHolds response.
message ListTagHoldsResponse {
  // A possibly paginated list of TagHolds.
  repeated TagHold tag_holds = 1;

  // Pagination token.
  //
  // If the result set is too large to fit in a single response, this token
  // is returned. It encodes the position of the current result cursor.
  // Feeding this value into a new list request with the `page_token` parameter
  // gives the next page of the results.
  //
  // When `next_page_token` is not filled in, there is no next page and
  // the list returned is the last page in the result set.
  //
  // Pagination tokens have a limited lifetime.
  string next_page_token = 2;
}
