// 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.recommender.v1;

import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/type/money.proto";

option csharp_namespace = "Google.Cloud.Recommender.V1";
option go_package = "cloud.google.com/go/recommender/apiv1/recommenderpb;recommenderpb";
option java_multiple_files = true;
option java_package = "com.google.cloud.recommender.v1";
option objc_class_prefix = "CREC";
option (google.api.resource_definition) = {
  type: "recommender.googleapis.com/Recommender"
  pattern: "projects/{project}/locations/{location}/recommenders/{recommender}"
  pattern: "billingAccounts/{billing_account}/locations/{location}/recommenders/{recommender}"
  pattern: "folders/{folder}/locations/{location}/recommenders/{recommender}"
  pattern: "organizations/{organization}/locations/{location}/recommenders/{recommender}"
};

// A recommendation along with a suggested action. E.g., a rightsizing
// recommendation for an underutilized VM, IAM role recommendations, etc
message Recommendation {
  option (google.api.resource) = {
    type: "recommender.googleapis.com/Recommendation"
    pattern: "projects/{project}/locations/{location}/recommenders/{recommender}/recommendations/{recommendation}"
    pattern: "billingAccounts/{billing_account}/locations/{location}/recommenders/{recommender}/recommendations/{recommendation}"
    pattern: "folders/{folder}/locations/{location}/recommenders/{recommender}/recommendations/{recommendation}"
    pattern: "organizations/{organization}/locations/{location}/recommenders/{recommender}/recommendations/{recommendation}"
  };

  // Recommendation priority levels.
  enum Priority {
    // Recommendation has unspecified priority.
    PRIORITY_UNSPECIFIED = 0;

    // Recommendation has P4 priority (lowest priority).
    P4 = 1;

    // Recommendation has P3 priority (second lowest priority).
    P3 = 2;

    // Recommendation has P2 priority (second highest priority).
    P2 = 3;

    // Recommendation has P1 priority (highest priority).
    P1 = 4;
  }

  // Reference to an associated insight.
  message InsightReference {
    // Insight resource name, e.g.
    // projects/[PROJECT_NUMBER]/locations/[LOCATION]/insightTypes/[INSIGHT_TYPE_ID]/insights/[INSIGHT_ID]
    string insight = 1;
  }

  // Name of recommendation.
  string name = 1;

  // Free-form human readable summary in English. The maximum length is 500
  // characters.
  string description = 2;

  // Contains an identifier for a subtype of recommendations produced for the
  // same recommender. Subtype is a function of content and impact, meaning a
  // new subtype might be added when significant changes to `content` or
  // `primary_impact.category` are introduced. See the Recommenders section
  // to see a list of subtypes for a given Recommender.
  //
  // Examples:
  //   For recommender = "google.iam.policy.Recommender",
  //   recommender_subtype can be one of "REMOVE_ROLE"/"REPLACE_ROLE"
  string recommender_subtype = 12;

  // Last time this recommendation was refreshed by the system that created it
  // in the first place.
  google.protobuf.Timestamp last_refresh_time = 4;

  // The primary impact that this recommendation can have while trying to
  // optimize for one category.
  Impact primary_impact = 5;

  // Optional set of additional impact that this recommendation may have when
  // trying to optimize for the primary category. These may be positive
  // or negative.
  repeated Impact additional_impact = 6;

  // Recommendation's priority.
  Priority priority = 17;

  // Content of the recommendation describing recommended changes to resources.
  RecommendationContent content = 7;

  // Information for state. Contains state and metadata.
  RecommendationStateInfo state_info = 10;

  // Fingerprint of the Recommendation. Provides optimistic locking when
  // updating states.
  string etag = 11;

  // Insights that led to this recommendation.
  repeated InsightReference associated_insights = 14;

  // Corresponds to a mutually exclusive group ID within a recommender.
  // A non-empty ID indicates that the recommendation belongs to a mutually
  // exclusive group. This means that only one recommendation within the group
  // is suggested to be applied.
  string xor_group_id = 18;
}

// Contains what resources are changing and how they are changing.
message RecommendationContent {
  // Operations to one or more Google Cloud resources grouped in such a way
  // that, all operations within one group are expected to be performed
  // atomically and in an order.
  repeated OperationGroup operation_groups = 2;

  // Condensed overview information about the recommendation.
  google.protobuf.Struct overview = 3;
}

// Group of operations that need to be performed atomically.
message OperationGroup {
  // List of operations across one or more resources that belong to this group.
  // Loosely based on RFC6902 and should be performed in the order they appear.
  repeated Operation operations = 1;
}

// Contains an operation for a resource loosely based on the JSON-PATCH format
// with support for:
//
// * Custom filters for describing partial array patch.
// * Extended path values for describing nested arrays.
// * Custom fields for describing the resource for which the operation is being
//   described.
// * Allows extension to custom operations not natively supported by RFC6902.
// See https://tools.ietf.org/html/rfc6902 for details on the original RFC.
message Operation {
  // Type of this operation. Contains one of 'add', 'remove', 'replace', 'move',
  // 'copy', 'test' and custom operations. This field is case-insensitive and
  // always populated.
  string action = 1;

  // Type of GCP resource being modified/tested. This field is always populated.
  // Example: cloudresourcemanager.googleapis.com/Project,
  // compute.googleapis.com/Instance
  string resource_type = 2;

  // Contains the fully qualified resource name. This field is always populated.
  // ex: //cloudresourcemanager.googleapis.com/projects/foo.
  string resource = 3;

  // Path to the target field being operated on. If the operation is at the
  // resource level, then path should be "/". This field is always populated.
  string path = 4;

  // Can be set with action 'copy' to copy resource configuration across
  // different resources of the same type. Example: A resource clone can be
  // done via action = 'copy', path = "/", from = "/",
  // source_resource = <source> and resource_name = <target>.
  // This field is empty for all other values of `action`.
  string source_resource = 5;

  // Can be set with action 'copy' or 'move' to indicate the source field within
  // resource or source_resource, ignored if provided for other operation types.
  string source_path = 6;

  // One of the fields in the following block will be set and intend to
  // describe a value for 'path' field.
  oneof path_value {
    // Value for the `path` field. Will be set for actions:'add'/'replace'.
    // Maybe set for action: 'test'. Either this or `value_matcher` will be set
    // for 'test' operation. An exact match must be performed.
    google.protobuf.Value value = 7;

    // Can be set for action 'test' for advanced matching for the value of
    // 'path' field. Either this or `value` will be set for 'test' operation.
    ValueMatcher value_matcher = 10;
  }

  // Set of filters to apply if `path` refers to array elements or nested array
  // elements in order to narrow down to a single unique element that is being
  // tested/modified.
  // This is intended to be an exact match per filter. To perform advanced
  // matching, use path_value_matchers.
  //
  // * Example:
  // ```
  // {
  //   "/versions/*/name" : "it-123"
  //   "/versions/*/targetSize/percent": 20
  // }
  // ```
  // * Example:
  // ```
  // {
  //   "/bindings/*/role": "roles/owner"
  //   "/bindings/*/condition" : null
  // }
  // ```
  // * Example:
  // ```
  // {
  //   "/bindings/*/role": "roles/owner"
  //   "/bindings/*/members/*" : ["x@example.com", "y@example.com"]
  // }
  // ```
  // When both path_filters and path_value_matchers are set, an implicit AND
  // must be performed.
  map<string, google.protobuf.Value> path_filters = 8;

  // Similar to path_filters, this contains set of filters to apply if `path`
  // field refers to array elements. This is meant to support value matching
  // beyond exact match. To perform exact match, use path_filters.
  // When both path_filters and path_value_matchers are set, an implicit AND
  // must be performed.
  map<string, ValueMatcher> path_value_matchers = 11;
}

// Contains various matching options for values for a GCP resource field.
message ValueMatcher {
  oneof match_variant {
    // To be used for full regex matching. The regular expression is using the
    // Google RE2 syntax (https://github.com/google/re2/wiki/Syntax), so to be
    // used with RE2::FullMatch
    string matches_pattern = 1;
  }
}

// Contains metadata about how much money a recommendation can save or incur.
message CostProjection {
  // An approximate projection on amount saved or amount incurred. Negative cost
  // units indicate cost savings and positive cost units indicate increase.
  // See google.type.Money documentation for positive/negative units.
  //
  // A user's permissions may affect whether the cost is computed using list
  // prices or custom contract prices.
  google.type.Money cost = 1;

  // Duration for which this cost applies.
  google.protobuf.Duration duration = 2;

  // The approximate cost savings in the billing account's local currency.
  google.type.Money cost_in_local_currency = 3;
}

// Contains various ways of describing the impact on Security.
message SecurityProjection {
  // Additional security impact details that is provided by the recommender.
  google.protobuf.Struct details = 2;
}

// Contains metadata about how much sustainability a recommendation can save or
// incur.
message SustainabilityProjection {
  // Carbon Footprint generated in kg of CO2 equivalent.
  // Chose kg_c_o2e so that the name renders correctly in camelCase (kgCO2e).
  double kg_c_o2e = 1;

  // Duration for which this sustainability applies.
  google.protobuf.Duration duration = 2;
}

// Contains information on the impact of a reliability recommendation.
message ReliabilityProjection {
  // The risk associated with the reliability issue.
  enum RiskType {
    // Default unspecified risk. Don't use directly.
    RISK_TYPE_UNSPECIFIED = 0;

    // Potential service downtime.
    SERVICE_DISRUPTION = 1;

    // Potential data loss.
    DATA_LOSS = 2;

    // Potential access denial. The service is still up but some or all clients
    // can't access it.
    ACCESS_DENY = 3;
  }

  // Reliability risks mitigated by this recommendation.
  repeated RiskType risks = 1;

  // Per-recommender projection.
  google.protobuf.Struct details = 2;
}

// Contains the impact a recommendation can have for a given category.
message Impact {
  // The category of the impact.
  enum Category {
    // Default unspecified category. Don't use directly.
    CATEGORY_UNSPECIFIED = 0;

    // Indicates a potential increase or decrease in cost.
    COST = 1;

    // Indicates a potential increase or decrease in security.
    SECURITY = 2;

    // Indicates a potential increase or decrease in performance.
    PERFORMANCE = 3;

    // Indicates a potential increase or decrease in manageability.
    MANAGEABILITY = 4;

    // Indicates a potential increase or decrease in sustainability.
    SUSTAINABILITY = 5;

    // Indicates a potential increase or decrease in reliability.
    RELIABILITY = 6;
  }

  // Category that is being targeted.
  Category category = 1;

  // Contains projections (if any) for this category.
  oneof projection {
    // Use with CategoryType.COST
    CostProjection cost_projection = 100;

    // Use with CategoryType.SECURITY
    SecurityProjection security_projection = 101;

    // Use with CategoryType.SUSTAINABILITY
    SustainabilityProjection sustainability_projection = 102;

    // Use with CategoryType.RELIABILITY
    ReliabilityProjection reliability_projection = 103;
  }
}

// Information for state. Contains state and metadata.
message RecommendationStateInfo {
  // Represents Recommendation State.
  enum State {
    // Default state. Don't use directly.
    STATE_UNSPECIFIED = 0;

    // Recommendation is active and can be applied. Recommendations content can
    // be updated by Google.
    //
    // ACTIVE recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED.
    ACTIVE = 1;

    // Recommendation is in claimed state. Recommendations content is
    // immutable and cannot be updated by Google.
    //
    // CLAIMED recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED.
    CLAIMED = 6;

    // Recommendation is in succeeded state. Recommendations content is
    // immutable and cannot be updated by Google.
    //
    // SUCCEEDED recommendations can be marked as SUCCEEDED, or FAILED.
    SUCCEEDED = 3;

    // Recommendation is in failed state. Recommendations content is immutable
    // and cannot be updated by Google.
    //
    // FAILED recommendations can be marked as SUCCEEDED, or FAILED.
    FAILED = 4;

    // Recommendation is in dismissed state. Recommendation content can be
    // updated by Google.
    //
    // DISMISSED recommendations can be marked as ACTIVE.
    DISMISSED = 5;
  }

  // The state of the recommendation, Eg ACTIVE, SUCCEEDED, FAILED.
  State state = 1;

  // A map of metadata for the state, provided by user or automations systems.
  map<string, string> state_metadata = 2;
}
