// Copyright 2026 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.biglake.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/field_info.proto";
import "google/api/httpbody.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";

option go_package = "cloud.google.com/go/biglake/apiv1/biglakepb;biglakepb";
option java_multiple_files = true;
option java_outer_classname = "IcebergRestCatalogProto";
option java_package = "com.google.cloud.biglake.v1";
option (google.api.resource_definition) = {
  type: "biglake.googleapis.com/Table"
  pattern: "projects/{project}/catalogs/{catalog}/namespaces/{namespace}/tables/{table}"
};
option (google.api.resource_definition) = {
  type: "biglake.googleapis.com/Namespace"
  pattern: "projects/{project}/catalogs/{catalog}/namespaces/{namespace}"
};
option (google.api.resource_definition) = {
  type: "secretmanager.googleapis.com/Secret"
  pattern: "projects/{project}/secrets/{secret}"
  pattern: "projects/{project}/locations/{location}/secrets/{secret}"
  plural: "secrets"
  singular: "secret"
};
option (google.api.resource_definition) = {
  type: "servicedirectory.googleapis.com/Service"
  pattern: "projects/{project}/locations/{location}/namespaces/{namespace}/services/{service}"
};

//
// Lakehouse runtime catalog supports the following catalog management methods:
// - GetIcebergCatalog
// - ListIcebergCatalogs
// - DeleteIcebergCatalog
// - UpdateIcebergCatalog
// - CreateIcebergCatalog
// - FailoverIcebergCatalog
service IcebergCatalogService {
  option (google.api.default_host) = "biglake.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/bigquery,"
      "https://www.googleapis.com/auth/cloud-platform";

  // GetIcebergCatalogConfig lists all catalog configuration settings. Most
  // importantly it contains the optional `endpoints` field which lists what
  // methods this catalog supports, since we are not supporting all the methods
  // right now.
  // It returns all the methods defined in this service (subject to project
  // config allowlisting).
  //
  // This is not a GCP resource.
  rpc GetIcebergCatalogConfig(GetIcebergCatalogConfigRequest)
      returns (IcebergCatalogConfig) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/config"
    };
  }

  // Lists Iceberg namespaces in the catalog. We only support one level of
  // nesting for namespaces.
  rpc ListIcebergNamespaces(ListIcebergNamespacesRequest)
      returns (ListIcebergNamespacesResponse) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/{api_parent=projects/*/catalogs/*}/namespaces"
    };
    option (google.api.method_signature) = "api_parent";
  }

  // Returns 204 if the namespace exists, 404 otherwise.
  rpc CheckIcebergNamespaceExists(GetIcebergNamespaceRequest)
      returns (google.protobuf.Empty) {
    option (google.api.method_signature) = "name";
  }

  // Gets an Iceberg namespace in the catalog (or checks if it exists, if the
  // method is HEAD).
  rpc GetIcebergNamespace(GetIcebergNamespaceRequest)
      returns (IcebergNamespace) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a namespace in the catalog.
  rpc CreateIcebergNamespace(CreateIcebergNamespaceRequest)
      returns (IcebergNamespace) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/v1/{parent=projects/*/catalogs/*}/namespaces"
      body: "iceberg_namespace"
    };
    option (google.api.method_signature) = "parent,iceberg_namespace";
  }

  // Returns 204, not 200 on success.
  rpc DeleteIcebergNamespace(DeleteIcebergNamespaceRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Updates namespace properties.
  rpc UpdateIcebergNamespace(UpdateIcebergNamespaceRequest)
      returns (UpdateIcebergNamespaceResponse) {
    option (google.api.http) = {
      patch: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*}/properties"
      body: "iceberg_namespace_update"
      additional_bindings {
        post: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*}/properties"
        body: "iceberg_namespace_update"
      }
    };
  }

  // Lists table identifiers (not *tables*) in the namespace.
  rpc ListIcebergTableIdentifiers(ListIcebergTableIdentifiersRequest)
      returns (ListIcebergTableIdentifiersResponse) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/{parent=projects/*/catalogs/*/namespaces/*}/tables"
    };
    option (google.api.method_signature) = "parent";
  }

  // Creates a table in the namespace.
  rpc CreateIcebergTable(CreateIcebergTableRequest)
      returns (google.api.HttpBody) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/v1/{parent=projects/*/catalogs/*/namespaces/*}/tables"
      body: "*"
    };
    option (google.api.method_signature) = "parent";
  }

  // Returns 204 if the table exists, 404 otherwise. This is a `HEAD` HTTP
  // method.
  rpc CheckIcebergTableExists(GetIcebergTableRequest)
      returns (google.protobuf.Empty) {
    option (google.api.method_signature) = "name";
  }

  // Deletes a table in the namespace.
  rpc DeleteIcebergTable(DeleteIcebergTableRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*/tables/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Gets a table in the namespace.
  rpc GetIcebergTable(GetIcebergTableRequest) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*/tables/*}"
    };
    option (google.api.method_signature) = "name,snapshots";
  }

  // Loads credentials for a table in the namespace.
  rpc LoadIcebergTableCredentials(GetIcebergTableRequest)
      returns (LoadIcebergTableCredentialsResponse) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*/tables/*}/credentials"
    };
    option (google.api.method_signature) = "name";
  }

  // This is CommitTable Iceberg API, which maps to `UpdateIcebergTable` in the
  // Google API nomenclature.
  rpc UpdateIcebergTable(UpdateIcebergTableRequest)
      returns (google.api.HttpBody) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*/tables/*}"
      body: "*"
    };
  }

  // Register a table using given metadata file location.
  rpc RegisterIcebergTable(RegisterIcebergTableRequest)
      returns (google.api.HttpBody) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/v1/{parent=projects/*/catalogs/*/namespaces/*}/register"
      body: "*"
    };
  }

  // Reports a metrics report for a table.
  rpc ReportIcebergTableMetrics(ReportIcebergTableMetricsRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/v1/{name=projects/*/catalogs/*/namespaces/*/tables/*}/metrics"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }

  // Returns the Iceberg REST Catalog configuration options.
  rpc GetIcebergCatalog(GetIcebergCatalogRequest) returns (IcebergCatalog) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/extensions/{name=projects/*/catalogs/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists the Iceberg REST Catalogs.
  rpc ListIcebergCatalogs(ListIcebergCatalogsRequest)
      returns (ListIcebergCatalogsResponse) {
    option (google.api.http) = {
      get: "/iceberg/v1/restcatalog/extensions/{parent=projects/*}/catalogs"
    };
    option (google.api.method_signature) = "parent";
  }

  // Deletes the Iceberg REST Catalog.
  // Delete does not delete a catalog that has contents -- at least one
  // namespace.
  //
  // Delete is not supported for all catalog types.
  rpc DeleteIcebergCatalog(DeleteIcebergCatalogRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/iceberg/v1/restcatalog/extensions/{name=projects/*/catalogs/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Update the Iceberg REST Catalog configuration options.
  rpc UpdateIcebergCatalog(UpdateIcebergCatalogRequest)
      returns (IcebergCatalog) {
    option (google.api.http) = {
      patch: "/iceberg/v1/restcatalog/extensions/{iceberg_catalog.name=projects/*/catalogs/*}"
      body: "iceberg_catalog"
    };
    option (google.api.method_signature) = "iceberg_catalog,update_mask";
  }

  // Creates the Iceberg REST Catalog.
  // Google Cloud Storage Bucket catalog id is the bucket for which the
  // catalog is created (e.g. `my-catalog` for `gs://my-catalog`).
  //
  // If the bucket does not exist, of the caller does not have bucket metadata
  // permissions, the catalog will not be created.
  rpc CreateIcebergCatalog(CreateIcebergCatalogRequest)
      returns (IcebergCatalog) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/extensions/{parent=projects/*}/catalogs"
      body: "iceberg_catalog"
    };
    option (google.api.method_signature) =
        "parent,iceberg_catalog,iceberg_catalog_id";
    option (google.api.method_signature) =
        "parent,iceberg_catalog,iceberg_catalog_id,primary_location";
  }

  // Failover the catalog to a new primary replica region.
  rpc FailoverIcebergCatalog(FailoverIcebergCatalogRequest)
      returns (FailoverIcebergCatalogResponse) {
    option (google.api.http) = {
      post: "/iceberg/v1/restcatalog/extensions/{name=projects/*/catalogs/*}:failover"
      body: "*"
    };
    option (google.api.method_signature) = "name,primary_replica";
  }
}

// The Iceberg REST Catalog information.
message IcebergCatalog {
  option (google.api.resource) = {
    type: "biglake.googleapis.com/Catalog"
    pattern: "projects/{project}/catalogs/{catalog}"
    plural: "catalogs"
    singular: "catalog"
  };

  // The replica of the Catalog.
  message Replica {
    // If the catalog is replicated to multiple regions, this enum describes the
    // current state of the replica.
    enum State {
      // The replica state is unknown.
      STATE_UNKNOWN = 0;

      // The replica is the writable primary.
      STATE_PRIMARY = 1;

      // The replica has been recently assigned as the primary, but not all
      // namespaces are writeable yet.
      STATE_PRIMARY_IN_PROGRESS = 2;

      // The replica is a read-only secondary replica.
      STATE_SECONDARY = 3;
    }

    // Output only. The region of the replica. For example "us-east1"
    string region = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. The current state of the replica.
    State state = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Configuration of location restrictions.
  message RestrictedLocationsConfig {
    // Optional. Additional Google Cloud Storage buckets and locations (e.g.,
    // `gs://my-other-bucket/...`) that are permitted for use by resources
    // within a catalog. This field is currently only used for BigLake catalogs.
    //
    // If `restricted_locations` is empty and unrestricted catalog creation is
    // enabled, all accessible locations are allowed.
    // Otherwise, only `default_location` and locations in this list are
    // allowed.
    repeated string restricted_locations = 1 [
      json_name = "restricted-locations",
      (google.api.field_behavior) = OPTIONAL
    ];
  }

  // Configuration options for a federated catalog.
  message FederatedCatalogOptions {
    // Unity Catalog info.
    message UnityCatalogInfo {
      // Required. The instance name is the first part of the URL when logging
      // into the Databricks deployment. For example, for a Databricks on GCP
      // workspace URL https://1.1.gcp.databricks.com, the instance name is
      // 1.1.gcp.databricks.com.
      optional string instance_name = 1
          [json_name = "instance-name", (google.api.field_behavior) = REQUIRED];

      // Required. The catalog name in Unity Catalog.
      optional string catalog_name = 2
          [json_name = "catalog-name", (google.api.field_behavior) = REQUIRED];

      // Optional. The application ID of the Databricks service principal that
      // will be used to access the Unity Catalog in the OIDC authentication
      // flow.
      optional string service_principal_application_id = 3 [
        json_name = "service-principal-application-id",
        (google.api.field_info).format = UUID4,
        (google.api.field_behavior) = OPTIONAL
      ];
    }

    // AWS Glue Catalog info. We support regional AWS Glue default account
    // catalog and S3 Table Buckets.
    message GlueCatalogInfo {
      // Required. Immutable. The warehouse to connect to a regional AWS Glue
      // Iceberg REST Catalog. For top level access, use the AWS account ID
      // (e.g. 111222333444). For an S3 table bucket, the warehouse is of the
      // form: 111222333444:s3tablescatalog/<table-bucket-name>. The URL to
      // access catalog will be
      // https://glue.{aws_region}.amazonaws.com/iceberg/v1?warehouse={warehouse}.
      // Must be non-empty and is immutable.
      optional string warehouse = 1 [
        (google.api.field_behavior) = REQUIRED,
        (google.api.field_behavior) = IMMUTABLE
      ];

      // Required. Immutable. The AWS region of the Glue catalog to connect to.
      // The region should be in the same geographical region and jurisdiction
      // as the federated catalog.
      // Must be non-empty and is immutable.
      optional string aws_region = 2 [
        json_name = "aws-region",
        (google.api.field_behavior) = REQUIRED,
        (google.api.field_behavior) = IMMUTABLE
      ];

      // Required. The AWS role ARN of the Glue catalog that the federated
      // catalog will assume to access the catalog. Must be non-empty. Can be
      // updated.
      optional string aws_role_arn = 3
          [json_name = "aws-role-arn", (google.api.field_behavior) = REQUIRED];
    }

    // Snowflake Catalog info.
    message SnowflakeCatalogInfo {
      // Required. The account identifier in Snowflake (See:
      // https://docs.snowflake.com/en/user-guide/admin-account-identifier). It
      // is the prefix to log into your Snowflake deployment URL. For example:
      // https://<account_identifier>.snowflakecomputing.com.
      optional string account_identifier = 1 [
        json_name = "account-identifier",
        (google.api.field_behavior) = REQUIRED
      ];

      // Required. The warehouse to connect to in Snowflake REST Catalog.
      // https://<account_identifier>.snowflakecomputing.com/polaris/api/catalog/v1/config?warehouse=<database_name>.
      //
      // This is the Snowflake database name containing the Iceberg metadata to
      // be federated.
      //
      // Must be non-empty.
      optional string warehouse = 2 [(google.api.field_behavior) = REQUIRED];

      // Optional. The specific Snowflake role name to request in the OAuth
      // token scope (via session:role:$ROLE) for the Iceberg REST Catalog
      // session. This role grants the GCP BigLake service account the necessary
      // permissions to interact with the Iceberg catalog, namespaces, and
      // tables.
      //
      // Note: The role provided here must be the DEFAULT_ROLE or be granted to,
      // the Snowflake service user mapped to the BigLake service account.
      optional string snowflake_role = 3 [
        json_name = "snowflake-role",
        (google.api.field_behavior) = OPTIONAL
      ];
    }

    // Schedule defines if and when metadata refresh should be scheduled.
    message RefreshSchedule {
      // Optional. The interval for refreshing metadata from the remote catalog.
      // If unset or if the value is <= 0, the background refresh will be
      // disabled. If this field is updated for an existing federated catalog,
      // the previous background refresh must complete before the new refresh
      // interval will take effect.
      optional google.protobuf.Duration refresh_interval = 1 [
        json_name = "refresh-interval",
        (google.api.field_behavior) = OPTIONAL
      ];
    }

    // The scope defines a subset of namespaces to be refreshed.
    message RefreshScope {
      // Optional. Filters to determine which namespaces are included in the
      // refresh process.
      // - empty list means include all namespaces.
      // - "[namespaces]" means include the specified namespaces.
      //   ['ns1', 'ns2']    : Discover only namespaces 'ns1' and 'ns2'.
      // The maximum number of namespace filters allowed is 32.
      repeated string namespace_filters = 1 [
        json_name = "namespace-filters",
        (google.api.field_behavior) = OPTIONAL
      ];
    }

    // Refresh configuration.
    message RefreshOptions {
      // Optional. Schedule defines if and when metadata refresh should be
      // scheduled.
      RefreshSchedule refresh_schedule = 1 [
        json_name = "refresh-schedule",
        (google.api.field_behavior) = OPTIONAL
      ];

      // Optional. Refresh scope configurations.
      RefreshScope refresh_scope = 2
          [json_name = "refresh-scope", (google.api.field_behavior) = OPTIONAL];
    }

    // Remote catalog background refresh status.
    message RefreshStatus {
      // Output only. When the catalog refresh has started, including
      // in-progress refreshes.
      optional google.protobuf.Timestamp start_time = 1
          [json_name = "start-time", (google.api.field_behavior) = OUTPUT_ONLY];

      // Output only. When the catalog refresh has ended, unset for in-progress
      // refreshes.
      optional google.protobuf.Timestamp end_time = 2
          [json_name = "end-time", (google.api.field_behavior) = OUTPUT_ONLY];

      // Output only. The status of the last background refresh operation, unset
      // for in-progress refreshes.
      optional google.rpc.Status status = 3
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Info specific to a remote Iceberg REST catalog.
    oneof remote_catalog_info {
      // Optional. Info specific to a Unity Catalog by Databricks.
      UnityCatalogInfo unity_catalog_info = 2 [
        json_name = "unity-catalog-info",
        (google.api.field_behavior) = OPTIONAL
      ];

      // Optional. Info specific to an AWS Glue Catalog.
      GlueCatalogInfo glue_catalog_info = 4 [
        json_name = "glue-catalog-info",
        (google.api.field_behavior) = OPTIONAL
      ];

      // Optional. Info specific to a Snowflake Catalog.
      SnowflakeCatalogInfo snowflake_catalog_info = 7 [
        json_name = "snowflake-catalog-info",
        (google.api.field_behavior) = OPTIONAL
      ];
    }

    // Optional. The secret resource name in Secret Manager, in the format
    // `projects/{project_id}/locations/{location}/secrets/{secret_id}` or
    // `projects/{project_id}/locations/{location}/secrets/{secret_id}/versions/{version_id}`.
    //
    // The project ID must match the catalog's project and location must match
    // the catalog's location.
    // If the version is not specified, the latest version will be used.
    //
    // This field is not used when
    // [google.cloud.biglake.v1main.IcebergCatalog.FederatedCatalogOptions.UnityCatalogInfo.service_principal_application_id][google.cloud.biglake.v1main.IcebergCatalog.FederatedCatalogOptions.UnityCatalogInfo.service_principal_application_id]
    // or
    // [google.cloud.biglake.v1main.IcebergCatalog.FederatedCatalogOptions.SnowflakeCatalogInfo.snowflake_role][google.cloud.biglake.v1main.IcebergCatalog.FederatedCatalogOptions.SnowflakeCatalogInfo.snowflake_role]
    // is set.
    optional string secret_name = 1 [
      json_name = "secret-name",
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "secretmanager.googleapis.com/Secret"
      }
    ];

    // Optional. The service directory resource name for routing traffic over a
    // private network connection through Cross-Cloud Interconnect, in the
    // format
    // `projects/{project_id}/locations/{location_id}/namespaces/{namespace_id}/services/{service_id}`.
    optional string service_directory_name = 5 [
      json_name = "service-directory-name",
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "servicedirectory.googleapis.com/Service"
      }
    ];

    // Optional. Refresh configuration.
    RefreshOptions refresh_options = 3
        [json_name = "refresh-options", (google.api.field_behavior) = OPTIONAL];

    // Output only. The status of the background refresh operations.
    RefreshStatus refresh_status = 6 [
      json_name = "refresh-status",
      (google.api.field_behavior) = OUTPUT_ONLY
    ];
  }

  // Determines the catalog type.
  enum CatalogType {
    // Default value. This value is unused.
    CATALOG_TYPE_UNSPECIFIED = 0;

    // Google Cloud Storage bucket catalog type.
    CATALOG_TYPE_GCS_BUCKET = 1;

    // BigLake catalog type.
    CATALOG_TYPE_BIGLAKE = 3;

    // Federated catalog type.
    CATALOG_TYPE_FEDERATED = 4;
  }

  // The credential mode used for the catalog.
  enum CredentialMode {
    // Default value. This value is unused.
    CREDENTIAL_MODE_UNSPECIFIED = 0;

    // End user credentials, default. The authenticating user must have access
    // to the catalog resources and the corresponding Google Cloud Storage
    // files.
    CREDENTIAL_MODE_END_USER = 1;

    // Use credential vending. The authenticating user must have access to the
    // catalog resources and the system will provide the caller with downscoped
    // credentials to access the Google Cloud Storage files. All table
    // operations in this mode would require `X-Iceberg-Access-Delegation`
    // header with `vended-credentials` value included. System will generate a
    // service account and the catalog administrator must grant the service
    // account appropriate permissions.
    //
    // See:
    // https://github.com/apache/iceberg/blob/931865ecaf40a827f9081dddb675bf1c95c05461/open-api/rest-catalog-open-api.yaml#L1854
    // for more details.
    CREDENTIAL_MODE_VENDED_CREDENTIALS = 2;
  }

  // Identifier. The catalog name, `projects/my-project/catalogs/my-catalog`.
  // This field is immutable.
  // This field is ignored for CreateIcebergCatalog.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Optional. The credential mode for the catalog.
  CredentialMode credential_mode = 2
      [json_name = "credential-mode", (google.api.field_behavior) = OPTIONAL];

  // Output only. The service account used for credential vending, output only.
  // Might be empty if Credential vending was never enabled for the catalog. For
  // federated catalogs, the service account will be always provisioned and will
  // be used to access the remote Iceberg REST Catalog using access to Secret
  // Manager secret or identity federation.
  string biglake_service_account = 3 [
    json_name = "biglake-service-account",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Output only. The unique ID of the service account. This is used for
  // federation scenarios.
  string biglake_service_account_unique_id = 14 [
    json_name = "biglake-service-account-id",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Required. The catalog type. Required for CreateIcebergCatalog.
  CatalogType catalog_type = 4
      [json_name = "catalog-type", (google.api.field_behavior) = REQUIRED];

  // Optional. The default storage location for the catalog, e.g.,
  // `gs://my-bucket`. For Google Cloud Storage bucket catalogs, this is output
  // only.
  //
  // For BigLake catalogs, this field must be provided and point to a
  // Google Cloud Storage bucket or a path within that bucket. This path serves
  // as the base directory for constructing the full path to a table's data and
  // metadata directories when a location is not specified at the namespace or
  // table level. The full path is formed by appending the namespace and table
  // identifiers to the default location.
  string default_location = 5
      [json_name = "default-location", (google.api.field_behavior) = OPTIONAL];

  // Output only. The GCP region(s) of the default location's bucket, e.g.
  // `us-central1`, `nam4` or `us`. This will contain one value for all
  // locations, except for the catalogs that are configured to use custom dual
  // region buckets, in which case it will contain the two regions of the
  // bucket. The region(s) of this field should be in the jurisdiction of or
  // nearby the primary location of the catalog.
  repeated string storage_regions = 10 [
    json_name = "storage-regions",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Output only. When the catalog was created.
  google.protobuf.Timestamp create_time = 7
      [json_name = "create-time", (google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. When the catalog was last updated.
  google.protobuf.Timestamp update_time = 8
      [json_name = "update-time", (google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The replicas for the catalog metadata.
  repeated Replica replicas = 9 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. A user-provided description of the catalog. The description must
  // be a UTF-8 string with a maximum length of 1024 characters.
  string description = 12 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Restricted locations configuration. This field is currently only
  // used for BigLake catalogs.
  //
  // If this field is unset, or if
  // `restricted_locations_config.restricted_locations` is empty, all
  // accessible locations are allowed. If
  // `restricted_locations_config.restricted_locations` is not empty, only
  // locations in `default_location` and
  // `restricted_locations_config.restricted_locations` are allowed.
  RestrictedLocationsConfig restricted_locations_config = 15 [
    json_name = "restricted-locations-config",
    (google.api.field_behavior) = OPTIONAL
  ];

  // Optional. Configuration options for federated catalogs.
  FederatedCatalogOptions federated_catalog_options = 13 [
    json_name = "federated-catalog-options",
    (google.api.field_behavior) = OPTIONAL
  ];
}

// The request message for the `CreateIcebergCatalog` API.
message CreateIcebergCatalogRequest {
  // Required. The parent resource where this catalog will be created.
  // Format: projects/{project_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Project"
    }
  ];

  // Required. The name of the catalog.
  string iceberg_catalog_id = 3 [
    json_name = "iceberg-catalog-id",
    (google.api.field_behavior) = REQUIRED
  ];

  // Required. The catalog to create.
  // The required fields for creation are:
  // - catalog_type.
  // Optionally: credential_mode can be provided, if Credential Vending is
  // desired.
  IcebergCatalog iceberg_catalog = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. The primary location where the catalog metadata will be stored.
  //
  // For Google Cloud Storage bucket catalogs and BigLake catalogs, if this
  // is not specified, then the region is inferred from the bucket's region
  // (`default_location` bucket for BigLake catalogs). If specified, the region
  // must be in jurisdiction (near the `default_location` bucket's region and
  // the `restricted_locations` buckets' regions for BigLake catalogs).
  //
  // For federated catalogs, this must be specified and be a Lakehouse-supported
  // location (https://docs.cloud.google.com/lakehouse/docs/locations). It
  // should be close to the remote catalog's location for the best
  // performance and cost.
  string primary_location = 4
      [json_name = "primary_location", (google.api.field_behavior) = OPTIONAL];
}

// The request message for the `DeleteIcebergCatalog` API.
message DeleteIcebergCatalogRequest {
  // Required. The catalog to delete.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Catalog" }
  ];
}

// The request message for the `UpdateIcebergCatalog` API.
message UpdateIcebergCatalogRequest {
  // Required. The catalog to update.
  IcebergCatalog iceberg_catalog = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The list of fields to update.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `GetIcebergCatalog` API.
message GetIcebergCatalogRequest {
  // Required. The catalog to get.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Catalog" }
  ];
}

// The request message for the `ListIcebergCatalogs` API.
message ListIcebergCatalogsRequest {
  // The enumeration of the views that can be returned.
  enum CatalogView {
    // Default/unset value. Same as BASIC.
    CATALOG_VIEW_UNSPECIFIED = 0;

    // Include only the name and catalog type.
    CATALOG_VIEW_BASIC = 1;

    // Include all fields of the catalog.
    CATALOG_VIEW_FULL = 2;
  }

  // Required. The parent resource where this catalog will be created.
  // Format: projects/{project_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "cloudresourcemanager.googleapis.com/Project"
    }
  ];

  // Optional. The view of the catalog to return.
  CatalogView view = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum number of catalogs to return. The service may return
  // fewer than this value.
  int32 page_size = 3
      [json_name = "page-size", (google.api.field_behavior) = OPTIONAL];

  // Optional. The page token, received from a previous `ListIcebergCatalogs`
  // call. Provide this to retrieve the subsequent page.
  string page_token = 4
      [json_name = "page-token", (google.api.field_behavior) = OPTIONAL];

  // Optional. The filter expression.
  // The only parameter currently supported is filtering based on the
  // `IcebergCatalog.catalog_type` field.
  //
  // Examples:
  // * `catalog_type = CATALOG_TYPE_BIGLAKE`
  // * `catalog_type != CATALOG_TYPE_GCS_BUCKET`
  // * `catalog_type = CATALOG_TYPE_BIGLAKE OR catalog_type =
  // CATALOG_TYPE_GCS_BUCKET`
  // * `NOT catalog_type = CATALOG_TYPE_GCS_BUCKET`
  string filter = 6 [(google.api.field_behavior) = OPTIONAL];
}

// The response message for the `ListIcebergCatalogs` API.
message ListIcebergCatalogsResponse {
  // Output only. The list of iceberg catalogs.
  repeated IcebergCatalog iceberg_catalogs = 1 [
    json_name = "iceberg-catalogs",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Output only. The next page token for pagination.
  string next_page_token = 2 [
    json_name = "next-page-token",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];

  // Output only. The list of unreachable cloud regions. If non-empty, the
  // result set might be incomplete.
  repeated string unreachable = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Request message for FailoverIcebergCatalog.
message FailoverIcebergCatalogRequest {
  // Required. The name of the catalog in the form
  // "projects/{project_id}/catalogs/{catalog_id}"
  string name = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The region being assigned as the new primary replica region. For
  // example "us-east1". This must be one of the replica regions in the
  // catalog's list of replicas marked as a "secondary".
  string primary_replica = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. If set, only validate the request, but do not perform the update.
  // This can be used to inspect the replication_time at any time, including
  // before performing a fail-over.
  bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If unset, wait for all data from the source region to replicate
  // to the new primary region before completing the failover, with no data loss
  // (also called "soft failover"). If set, failover immediately, accepting the
  // loss of any data committed in the source region after this timestamp, that
  // has not yet replicated. If any data committed before this time has not
  // replicated, the failover will not be performed and an error will be
  // returned (also called "hard failover").
  google.protobuf.Timestamp conditional_failover_replication_time = 4
      [(google.api.field_behavior) = OPTIONAL];
}

// Response message for FailoverIcebergCatalog.
message FailoverIcebergCatalogResponse {
  // Output only. The min timestamp for which all namespaces and table metadata
  // have been replicated in the region specified as the new primary_replica.
  // Some resources may have been replicated more recently than this timestamp.
  // If empty, the replica has just been created and has not yet been fully
  // initialized. NOTE: When the Cloud Storage replication watermark is
  // available, this will represent both catalog metadata and Cloud Storage
  // data.
  google.protobuf.Timestamp replication_time = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The update message for the `UpdateIcebergTable` API.
message UpdateIcebergTableRequest {
  // Required. Table to commit in the format:
  // `projects/{projectId}/catalogs/{catalogId}/namespaces/{namespace}/tables/{table}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Table" }
  ];

  // Required.
  google.api.HttpBody http_body = 2 [(google.api.field_behavior) = REQUIRED];
}

// The request message for the `GetIcebergTable` API.
message GetIcebergTableRequest {
  // Required. Table to get in the format:
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Table" }
  ];

  // Optional. What snapshot to get. Valid only for GetIcebergTable.
  string snapshots = 2 [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `DeleteIcebergTable` API.
message DeleteIcebergTableRequest {
  // Required. Table to delete in the format:
  // `projects/{project_id}/namespaces/{namespace}/tables/{table}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Table" }
  ];

  // Optional. If true we'll delete both the table and the data. Currently
  // purgin data is not supported.
  bool purge_requested = 2 [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `CreateIcebergTable` API.
message CreateIcebergTableRequest {
  // Required. The parent resource where this table will be created.
  // Format: projects/{project_id}/catalogs/{catalog_id}/namespaces/{namespace}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];

  // Required.
  google.api.HttpBody http_body = 3 [(google.api.field_behavior) = REQUIRED];
}

// The request message for the `RegisterIcebergTable` API.
message RegisterIcebergTableRequest {
  // Required. Table to register in the format:
  // `projects/{project_id}/catalogs/{catalog_id}/namespaces/{namespace}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];

  // Required. The name of the table to register.
  string name = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The metadata location of the table.
  string metadata_location = 3
      [json_name = "metadata-location", (google.api.field_behavior) = REQUIRED];

  // Optional. Whether to overwrite the table if it already exists. Default is
  // false.
  bool overwrite = 4 [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `ReportIcebergTableMetrics` API.
message ReportIcebergTableMetricsRequest {
  // Required. Table to report metrics for in the format:
  // `projects/{project_id}/namespaces/{namespace}/tables/{table}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Table" }
  ];

  // Required.
  google.api.HttpBody http_body = 2 [(google.api.field_behavior) = REQUIRED];
}

// The request message for the `ListIcebergTableIdentifiers` API.
message ListIcebergTableIdentifiersRequest {
  // Optional. PageToken for pagination.
  string page_token = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Page size for pagination.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. The namespace to list tables from.
  string parent = 3 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];
}

// The table identifier.
message TableIdentifier {
  // The namespace of the table. This is always 1 element, since we don't
  // support nested namespaces.
  repeated string namespace = 1 [(google.api.resource_reference) = {
    type: "biglake.googleapis.com/Namespace"
  }];

  // The table name.
  string name = 2;
}

// The response message for the `ListIcebergTableIdentifiers` API.
message ListIcebergTableIdentifiersResponse {
  // Output only. The list of table identifiers.
  repeated TableIdentifier identifiers = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The next page token for pagination.
  string next_page_token = 2 [
    json_name = "next-page-token",
    (google.api.field_behavior) = OUTPUT_ONLY
  ];
}

// The request message for the `UpdateIcebergNamespace` API.
message IcebergNamespaceUpdate {
  // Optional. Keys of the properties to remove.
  repeated string removals = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. List of properties to update or add.
  map<string, string> updates = 3 [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `UpdateIcebergNamespace` API.
message UpdateIcebergNamespaceRequest {
  // Required. The namespace to update.
  //
  // The namespace's `name` field is used to identify the namespace to update.
  // Format: projects/{project_id}/catalogs/{catalog_id}/namespaces/{namespace}
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];

  // Required. The update to apply to the namespace.
  IcebergNamespaceUpdate iceberg_namespace_update = 2
      [(google.api.field_behavior) = REQUIRED];
}

// The response message for the `UpdateIcebergNamespace` API.
message UpdateIcebergNamespaceResponse {
  // Output only. List of properties that were removed.
  repeated string removed = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. List of properties that were added or updated.
  repeated string updated = 2
      [json_name = "added", (google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. List of properties that were requested to be removed, but were
  // not found.
  repeated string missing = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The request message for the `DeleteIcebergNamespace` API.
message DeleteIcebergNamespaceRequest {
  // Required. Iceberg namespace to delete in the format:
  // `projects/{project_id}/catalogs/{catalog_id}/namespaces/{namespace}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];
}

// The namespace object to create.
message IcebergNamespace {
  // Required. The name of the namespace.
  repeated string namespace = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The optional properties of the namespace.
  map<string, string> properties = 2 [(google.api.field_behavior) = OPTIONAL];
}

// The request message for the `CreateIcebergNamespace` API.
message CreateIcebergNamespaceRequest {
  // Required. The parent resource where this namespace will be created.
  // Format: projects/{project_id}/catalogs/{catalog_id}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "biglake.googleapis.com/Catalog" }
  ];

  // Required. The namespace to create.
  IcebergNamespace iceberg_namespace = 2
      [json_name = "namespace", (google.api.field_behavior) = REQUIRED];
}

// The request message for the `GetIcebergCatalogConfig` API.
message GetIcebergCatalogConfigRequest {
  // Required. Warehouse location or identifier to request from the service.
  string warehouse = 1 [(google.api.field_behavior) = REQUIRED];
}

// The iceberg catalog configuration.
message IcebergCatalogConfig {
  // Output only. Properties that should be used to override client
  // configuration; applied after defaults and client configuration. Required,
  // even if empty.
  map<string, string> overrides = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Properties that should be used as default configuration;
  // applied before client configuration. Required, even if empty.
  map<string, string> defaults = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Endpoints, required, must not be empty.
  repeated string endpoints = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The request message for the `GetIcebergNamespace` API.
message GetIcebergNamespaceRequest {
  // Required. Iceberg namespace to fetch in the format:
  // `projects/{project_id}/catalogs/{catalog_id}/namespaces/{namespace}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "biglake.googleapis.com/Namespace"
    }
  ];
}

// ListIcebergNamespacesRequest
message ListIcebergNamespacesRequest {
  // Optional. Specify the page_token returned in the previous response to
  // retrieve the next page of results.
  string page_token = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. For servers that support pagination, this signals an upper bound
  // of the number of results that a client will receive. For servers that do
  // not support pagination, clients may receive results larger than the
  // indicated `pageSize`. Defaults to 100 if not set.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Required. The parent from the resource path.
  string api_parent = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. An optional namespace, underneath which to list namespaces. If
  // not provided or empty, all top-level namespaces should be listed. If parent
  // is a multipart namespace, the parts must be separated by the unit separator
  // (`0x1F`) byte.
  // Not a real parent, so ST_NOT_REQUIRED.
  string parent = 4 [(google.api.field_behavior) = OPTIONAL];
}

// The response message for the `ListIcebergNamespaces` API.
message ListIcebergNamespacesResponse {
  // The list of namespaces.
  repeated google.protobuf.ListValue namespaces = 1;

  // The next page token for pagination.
  string next_page_token = 2 [json_name = "next-page-token"];

  // Output only. A list of skipped locations that were unreachable. If
  // non-empty, the result set might be incomplete.
  repeated string unreachable = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The storage credential for a path in the table.
message StorageCredential {
  // Indicates a storage location prefix where the credential is relevant.
  string prefix = 1;

  // The credentials for the storage location. The keys that are populated are:
  // - `gcs.oauth2.token`
  // - `gcs.oauth2.token_expires_at`
  // - `expiration-time` (to support federation from Polaris).
  map<string, string> config = 2;
}

// The response message for the `LoadCredentials` API.
message LoadIcebergTableCredentialsResponse {
  // The credentials for the table assigned to the caller.
  repeated StorageCredential storage_credentials = 1
      [json_name = "storage-credentials"];
}
