// Copyright 2022 Luca Casonato. All rights reserved. MIT license.
/**
 * Agent Identity Credentials API Client for Deno
 * ==============================================
 * 
 * agentidentitycredentials.googleapis.com API.
 * 
 * Docs: https://cloud.google.com/iam/docs/
 * Source: https://googleapis.deno.dev/v1/agentidentitycredentials:v1.ts
 */

import { auth, CredentialsClient, GoogleAuth, request } from "/_/base@v1/mod.ts";
export { auth, GoogleAuth };
export type { CredentialsClient };

/**
 * agentidentitycredentials.googleapis.com API.
 */
export class AgentIdentityCredentials {
  #client: CredentialsClient | undefined;
  #baseUrl: string;

  constructor(client?: CredentialsClient, baseUrl: string = "https://agentidentitycredentials.googleapis.com/") {
    this.#client = client;
    this.#baseUrl = baseUrl;
  }

  /**
   * Finalizes the credentials after a successful consent flow.
   *
   * @param authProvider Required. The resource name of the AuthProvider. Format: `projects/{project}/locations/{location}/authProviders/{auth_provider}`
   */
  async projectsLocationsAuthProvidersCredentialsFinalize(authProvider: string, req: GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest): Promise<GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsResponse> {
    req = serializeGoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest(req);
    const url = new URL(`${this.#baseUrl}v1/${ authProvider }/credentials:finalize`);
    const body = JSON.stringify(req);
    const data = await request(url.href, {
      client: this.#client,
      method: "POST",
      body,
    });
    return data as GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsResponse;
  }

  /**
   * Retrieves authorization credentials for an authprovider, or indicates what
   * action needs to be taken to obtain credentials. If the `token` field in the
   * response is populated, credential retrieval was successful. If one of the
   * fields in the `status` oneof is populated, further action is required to
   * obtain credentials, such as redirecting the user for consent. View comments
   * on `RetrieveCredentialsResponse` for more information.
   *
   * @param authProvider Required. The parent resource name of the AuthProvider. Format: `projects/{project}/locations/{location}/authProviders/{auth_provider}`
   */
  async projectsLocationsAuthProvidersCredentialsRetrieve(authProvider: string, req: GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsRequest): Promise<GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse> {
    const url = new URL(`${this.#baseUrl}v1/${ authProvider }/credentials:retrieve`);
    const body = JSON.stringify(req);
    const data = await request(url.href, {
      client: this.#client,
      method: "POST",
      body,
    });
    return deserializeGoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse(data);
  }
}

/**
 * Indicates the user has rejected the permission delegation or cancelled the
 * request.
 */
export interface GoogleCloudAgentidentitycredentialsV1_ConsentRejected {
}

/**
 * Request message for FinalizeCredentials.
 */
export interface GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest {
  /**
   * Required. The same consent_nonce value that was provided during redirect
   * in the UriConsentRequired metadata.
   */
  consentNonce?: string;
  /**
   * Required. The identity of the end user.
   */
  userId?: string;
  /**
   * Required. The encrypted state passed back from the consent flow.
   */
  userIdValidationState?: Uint8Array;
}

function serializeGoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest(data: any): GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest {
  return {
    ...data,
    userIdValidationState: data["userIdValidationState"] !== undefined ? encodeBase64(data["userIdValidationState"]) : undefined,
  };
}

function deserializeGoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest(data: any): GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsRequest {
  return {
    ...data,
    userIdValidationState: data["userIdValidationState"] !== undefined ? decodeBase64(data["userIdValidationState"] as string) : undefined,
  };
}

/**
 * Response message for FinalizeCredentials. Intentionally empty
 */
export interface GoogleCloudAgentidentitycredentialsV1_FinalizeCredentialsResponse {
}

/**
 * Indicates that the credential retrieval is pending. The caller should retry
 * the RetrieveCredentials request after some time.
 */
export interface GoogleCloudAgentidentitycredentialsV1_Pending {
}

/**
 * Request message for RetrieveCredentials.
 */
export interface GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsRequest {
  /**
   * Optional. The URI to redirect the user to after consent is completed. This
   * field is required for authproviders using the 3-legged OAuth flow. For
   * other authprovider types, this field is unused but not rejected.
   */
  continueUri?: string;
  /**
   * Optional. Input only. Set this field only if the previous token was
   * expired or invalid. This value must be the full, previously returned token
   * string. Will trigger a refresh of the access token with a stored refresh
   * token, if possible, or a new consent flow.
   */
  forceRefreshToken?: string;
  /**
   * Optional. The OAuth scopes required for this access.
   */
  scopes?: string[];
  /**
   * Required. The identity of the end user.
   */
  userId?: string;
}

/**
 * Response message for RetrieveCredentials. Contains the access tokens and
 * related artifacts.
 */
export interface GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse {
  /**
   * Message indicating consent was rejected.
   */
  consentRejected?: GoogleCloudAgentidentitycredentialsV1_ConsentRejected;
  /**
   * Message indicating credential retrieval is pending.
   */
  pending?: GoogleCloudAgentidentitycredentialsV1_Pending;
  /**
   * Message indicating credentials were successfully retrieved.
   */
  success?: GoogleCloudAgentidentitycredentialsV1_Success;
  /**
   * Message indicating uri based consent is required.
   */
  uriConsentRequired?: GoogleCloudAgentidentitycredentialsV1_UriConsentRequired;
}

function serializeGoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse(data: any): GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse {
  return {
    ...data,
    success: data["success"] !== undefined ? serializeGoogleCloudAgentidentitycredentialsV1_Success(data["success"]) : undefined,
  };
}

function deserializeGoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse(data: any): GoogleCloudAgentidentitycredentialsV1_RetrieveCredentialsResponse {
  return {
    ...data,
    success: data["success"] !== undefined ? deserializeGoogleCloudAgentidentitycredentialsV1_Success(data["success"]) : undefined,
  };
}

/**
 * Message indicating successful retrieval of credentials.
 */
export interface GoogleCloudAgentidentitycredentialsV1_Success {
  /**
   * The expiration time of the token. This does not guarantee that the token
   * will be valid until this time, since the token could be revoked earlier.
   * There could also be clock skew between the auth provider and the client so
   * it may expire slightly earlier. If not set, the token might be permanent or
   * it may be that the service does not (or cannot) know when it will expire.
   */
  expireTime?: Date;
  /**
   * The HTTP header name where the token should be placed.
   */
  header?: string;
  /**
   * The scopes actually associated with the retrieved token. End users may
   * have rejected some requested scopes, or the third-party authorization
   * servers can return a different set of scopes than what was asked for.
   * Callers should verify that all required scopes for their intended use are
   * included in this list.
   */
  scopes?: string[];
  /**
   * The retrieved access token or credential for the end user. On MCPTool
   * call, for an invalid token OAuth spec says this should return 401 or 403,
   * but MCPServers may implement this differently. If you get any flavor of
   * `PERMISSION_DENIED`, retry your original request to RetrieveCredentials
   * with force_refresh_token set to the expired/invalid token string, which
   * will fetch a new token or initiate a new consent flow.
   */
  token?: string;
}

function serializeGoogleCloudAgentidentitycredentialsV1_Success(data: any): GoogleCloudAgentidentitycredentialsV1_Success {
  return {
    ...data,
    expireTime: data["expireTime"] !== undefined ? data["expireTime"].toISOString() : undefined,
  };
}

function deserializeGoogleCloudAgentidentitycredentialsV1_Success(data: any): GoogleCloudAgentidentitycredentialsV1_Success {
  return {
    ...data,
    expireTime: data["expireTime"] !== undefined ? new Date(data["expireTime"]) : undefined,
  };
}

/**
 * Indicates that the user must visit the provided URI to consent to delegate
 * permission to the agent to act on their behalf. The caller can either poll
 * the `RetrieveCredentials` method, or await the /ValidateUserId callback
 */
export interface GoogleCloudAgentidentitycredentialsV1_UriConsentRequired {
  /**
   * Output only. The URL where the user should be redirected to grant consent.
   * This will always be present.
   */
  readonly authorizationUri?: string;
  /**
   * Output only. A one-time, randomly generated value that validates the
   * entire consent flow is handled by a single user, avoiding CSRF attacks. It
   * must be submitted with the FinalizeCredentials request to complete the
   * OAuth exchange. This will always be present. Implemented per
   * https://www.rfc-editor.org/rfc/rfc6819#section-5.3.5
   */
  readonly consentNonce?: string;
  /**
   * Output only. The unique ID of the credentials retrieval operation.
   */
  readonly uid?: string;
}

function decodeBase64(b64: string): Uint8Array {
  const binString = atob(b64);
  const size = binString.length;
  const bytes = new Uint8Array(size);
  for (let i = 0; i < size; i++) {
    bytes[i] = binString.charCodeAt(i);
  }
  return bytes;
}

const base64abc = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"];
/**
 * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
 * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation
 * @param data
 */
function encodeBase64(uint8: Uint8Array): string {
  let result = "", i;
  const l = uint8.length;
  for (i = 2; i < l; i += 3) {
    result += base64abc[uint8[i - 2] >> 2];
    result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
    result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)];
    result += base64abc[uint8[i] & 0x3f];
  }
  if (i === l + 1) {
    // 1 octet yet to write
    result += base64abc[uint8[i - 2] >> 2];
    result += base64abc[(uint8[i - 2] & 0x03) << 4];
    result += "==";
  }
  if (i === l) {
    // 2 octets yet to write
    result += base64abc[uint8[i - 2] >> 2];
    result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)];
    result += base64abc[(uint8[i - 1] & 0x0f) << 2];
    result += "=";
  }
  return result;
}
