// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { APIResource } from '../../../resource';
import { isRequestOptions } from '../../../core';
import * as Core from '../../../core';
import { CloudflareError } from '../../../error';
import { V4PagePaginationArray, type V4PagePaginationArrayParams } from '../../../pagination';

export class ServiceTokens extends APIResource {
  /**
   * Generates a new service token. **Note:** This is the only time you can get the
   * Client Secret. If you lose the Client Secret, you will have to rotate the Client
   * Secret or create a new service token.
   *
   * @example
   * ```ts
   * const serviceToken =
   *   await client.zeroTrust.access.serviceTokens.create({
   *     name: 'CI/CD token',
   *     account_id: 'account_id',
   *   });
   * ```
   */
  create(
    params: ServiceTokenCreateParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceTokenCreateResponse> {
    const {
      account_id = this._client.accountId ?? undefined,
      zone_id = this._client.zoneId ?? undefined,
      ...body
    } = params;
    if (!account_id && !zone_id) {
      throw new CloudflareError('You must provide either account_id or zone_id.');
    }
    if (account_id && zone_id) {
      throw new CloudflareError('You cannot provide both account_id and zone_id.');
    }
    const { accountOrZone, accountOrZoneId } =
      account_id ?
        {
          accountOrZone: 'accounts',
          accountOrZoneId: account_id,
        }
      : {
          accountOrZone: 'zones',
          accountOrZoneId: zone_id,
        };
    return (
      this._client.post(`/${accountOrZone}/${accountOrZoneId}/access/service_tokens`, {
        body,
        ...options,
      }) as Core.APIPromise<{ result: ServiceTokenCreateResponse }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Updates a configured service token.
   *
   * @example
   * ```ts
   * const serviceToken =
   *   await client.zeroTrust.access.serviceTokens.update(
   *     'f174e90a-fafe-4643-bbbc-4a0ed4fc8415',
   *     { account_id: 'account_id' },
   *   );
   * ```
   */
  update(
    serviceTokenId: string,
    params: ServiceTokenUpdateParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken> {
    const {
      account_id = this._client.accountId ?? undefined,
      zone_id = this._client.zoneId ?? undefined,
      ...body
    } = params;
    if (!account_id && !zone_id) {
      throw new CloudflareError('You must provide either account_id or zone_id.');
    }
    if (account_id && zone_id) {
      throw new CloudflareError('You cannot provide both account_id and zone_id.');
    }
    const { accountOrZone, accountOrZoneId } =
      account_id ?
        {
          accountOrZone: 'accounts',
          accountOrZoneId: account_id,
        }
      : {
          accountOrZone: 'zones',
          accountOrZoneId: zone_id,
        };
    return (
      this._client.put(`/${accountOrZone}/${accountOrZoneId}/access/service_tokens/${serviceTokenId}`, {
        body,
        ...options,
      }) as Core.APIPromise<{ result: ServiceToken }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Lists all service tokens.
   *
   * @example
   * ```ts
   * // Automatically fetches more pages as needed.
   * for await (const serviceToken of client.zeroTrust.access.serviceTokens.list(
   *   { account_id: 'account_id' },
   * )) {
   *   // ...
   * }
   * ```
   */
  list(
    params?: ServiceTokenListParams,
    options?: Core.RequestOptions,
  ): Core.PagePromise<ServiceTokensV4PagePaginationArray, ServiceToken>;
  list(options?: Core.RequestOptions): Core.PagePromise<ServiceTokensV4PagePaginationArray, ServiceToken>;
  list(
    params: ServiceTokenListParams | Core.RequestOptions = {},
    options?: Core.RequestOptions,
  ): Core.PagePromise<ServiceTokensV4PagePaginationArray, ServiceToken> {
    if (isRequestOptions(params)) {
      return this.list({}, params);
    }
    const {
      account_id = this._client.accountId ?? undefined,
      zone_id = this._client.zoneId ?? undefined,
      ...query
    } = params;
    if (!account_id && !zone_id) {
      throw new CloudflareError('You must provide either account_id or zone_id.');
    }
    if (account_id && zone_id) {
      throw new CloudflareError('You cannot provide both account_id and zone_id.');
    }
    const { accountOrZone, accountOrZoneId } =
      account_id ?
        {
          accountOrZone: 'accounts',
          accountOrZoneId: account_id,
        }
      : {
          accountOrZone: 'zones',
          accountOrZoneId: zone_id,
        };
    return this._client.getAPIList(
      `/${accountOrZone}/${accountOrZoneId}/access/service_tokens`,
      ServiceTokensV4PagePaginationArray,
      { query, ...options },
    );
  }

  /**
   * Deletes a service token.
   *
   * @example
   * ```ts
   * const serviceToken =
   *   await client.zeroTrust.access.serviceTokens.delete(
   *     'f174e90a-fafe-4643-bbbc-4a0ed4fc8415',
   *     { account_id: 'account_id' },
   *   );
   * ```
   */
  delete(
    serviceTokenId: string,
    params?: ServiceTokenDeleteParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken>;
  delete(serviceTokenId: string, options?: Core.RequestOptions): Core.APIPromise<ServiceToken>;
  delete(
    serviceTokenId: string,
    params: ServiceTokenDeleteParams | Core.RequestOptions = {},
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken> {
    if (isRequestOptions(params)) {
      return this.delete(serviceTokenId, {}, params);
    }
    const { account_id = this._client.accountId ?? undefined, zone_id = this._client.zoneId ?? undefined } =
      params;
    if (!account_id && !zone_id) {
      throw new CloudflareError('You must provide either account_id or zone_id.');
    }
    if (account_id && zone_id) {
      throw new CloudflareError('You cannot provide both account_id and zone_id.');
    }
    const { accountOrZone, accountOrZoneId } =
      account_id ?
        {
          accountOrZone: 'accounts',
          accountOrZoneId: account_id,
        }
      : {
          accountOrZone: 'zones',
          accountOrZoneId: zone_id,
        };
    return (
      this._client.delete(
        `/${accountOrZone}/${accountOrZoneId}/access/service_tokens/${serviceTokenId}`,
        options,
      ) as Core.APIPromise<{ result: ServiceToken }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Fetches a single service token.
   *
   * @example
   * ```ts
   * const serviceToken =
   *   await client.zeroTrust.access.serviceTokens.get(
   *     'f174e90a-fafe-4643-bbbc-4a0ed4fc8415',
   *     { account_id: 'account_id' },
   *   );
   * ```
   */
  get(
    serviceTokenId: string,
    params?: ServiceTokenGetParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken>;
  get(serviceTokenId: string, options?: Core.RequestOptions): Core.APIPromise<ServiceToken>;
  get(
    serviceTokenId: string,
    params: ServiceTokenGetParams | Core.RequestOptions = {},
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken> {
    if (isRequestOptions(params)) {
      return this.get(serviceTokenId, {}, params);
    }
    const { account_id = this._client.accountId ?? undefined, zone_id = this._client.zoneId ?? undefined } =
      params;
    if (!account_id && !zone_id) {
      throw new CloudflareError('You must provide either account_id or zone_id.');
    }
    if (account_id && zone_id) {
      throw new CloudflareError('You cannot provide both account_id and zone_id.');
    }
    const { accountOrZone, accountOrZoneId } =
      account_id ?
        {
          accountOrZone: 'accounts',
          accountOrZoneId: account_id,
        }
      : {
          accountOrZone: 'zones',
          accountOrZoneId: zone_id,
        };
    return (
      this._client.get(
        `/${accountOrZone}/${accountOrZoneId}/access/service_tokens/${serviceTokenId}`,
        options,
      ) as Core.APIPromise<{ result: ServiceToken }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Refreshes the expiration of a service token.
   *
   * @example
   * ```ts
   * const serviceToken =
   *   await client.zeroTrust.access.serviceTokens.refresh(
   *     'f174e90a-fafe-4643-bbbc-4a0ed4fc8415',
   *     { account_id: '023e105f4ecef8ad9ca31a8372d0c353' },
   *   );
   * ```
   */
  refresh(
    serviceTokenId: string,
    params?: ServiceTokenRefreshParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken>;
  refresh(serviceTokenId: string, options?: Core.RequestOptions): Core.APIPromise<ServiceToken>;
  refresh(
    serviceTokenId: string,
    params: ServiceTokenRefreshParams | Core.RequestOptions = {},
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceToken> {
    if (isRequestOptions(params)) {
      return this.refresh(serviceTokenId, {}, params);
    }
    const { account_id = this._client.accountId } = params;
    return (
      this._client.post(
        `/accounts/${account_id}/access/service_tokens/${serviceTokenId}/refresh`,
        options,
      ) as Core.APIPromise<{ result: ServiceToken }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Generates a new Client Secret for a service token and revokes the old one.
   *
   * @example
   * ```ts
   * const response =
   *   await client.zeroTrust.access.serviceTokens.rotate(
   *     'f174e90a-fafe-4643-bbbc-4a0ed4fc8415',
   *     { account_id: '023e105f4ecef8ad9ca31a8372d0c353' },
   *   );
   * ```
   */
  rotate(
    serviceTokenId: string,
    params?: ServiceTokenRotateParams,
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceTokenRotateResponse>;
  rotate(serviceTokenId: string, options?: Core.RequestOptions): Core.APIPromise<ServiceTokenRotateResponse>;
  rotate(
    serviceTokenId: string,
    params: ServiceTokenRotateParams | Core.RequestOptions = {},
    options?: Core.RequestOptions,
  ): Core.APIPromise<ServiceTokenRotateResponse> {
    if (isRequestOptions(params)) {
      return this.rotate(serviceTokenId, {}, params);
    }
    const { account_id = this._client.accountId, ...body } = params;
    return (
      this._client.post(`/accounts/${account_id}/access/service_tokens/${serviceTokenId}/rotate`, {
        body,
        ...options,
      }) as Core.APIPromise<{ result: ServiceTokenRotateResponse }>
    )._thenUnwrap((obj) => obj.result);
  }
}

export class ServiceTokensV4PagePaginationArray extends V4PagePaginationArray<ServiceToken> {}

export interface ServiceToken {
  /**
   * The ID of the service token.
   */
  id?: string;

  /**
   * The Client ID for the service token. Access will check for this value in the
   * `CF-Access-Client-ID` request header.
   */
  client_id?: string;

  /**
   * The duration for how long the service token will be valid. Must be in the format
   * `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s, m, h. The
   * default is 1 year in hours (8760h).
   */
  duration?: string;

  expires_at?: string;

  /**
   * The name of the service token.
   */
  name?: string;
}

export interface ServiceTokenCreateResponse {
  /**
   * The ID of the service token.
   */
  id?: string;

  /**
   * The Client ID for the service token. Access will check for this value in the
   * `CF-Access-Client-ID` request header.
   */
  client_id?: string;

  /**
   * The Client Secret for the service token. Access will check for this value in the
   * `CF-Access-Client-Secret` request header.
   */
  client_secret?: string;

  /**
   * The duration for how long the service token will be valid. Must be in the format
   * `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s, m, h. The
   * default is 1 year in hours (8760h).
   */
  duration?: string;

  /**
   * The name of the service token.
   */
  name?: string;
}

export interface ServiceTokenRotateResponse {
  /**
   * The ID of the service token.
   */
  id?: string;

  /**
   * The Client ID for the service token. Access will check for this value in the
   * `CF-Access-Client-ID` request header.
   */
  client_id?: string;

  /**
   * The Client Secret for the service token. Access will check for this value in the
   * `CF-Access-Client-Secret` request header.
   */
  client_secret?: string;

  /**
   * The duration for how long the service token will be valid. Must be in the format
   * `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s, m, h. The
   * default is 1 year in hours (8760h).
   */
  duration?: string;

  /**
   * The name of the service token.
   */
  name?: string;
}

export interface ServiceTokenCreateParams {
  /**
   * Body param: The name of the service token.
   */
  name: string;

  /**
   * Path param: The Account ID to use for this endpoint. Mutually exclusive with the
   * Zone ID.
   */
  account_id?: string;

  /**
   * Path param: The Zone ID to use for this endpoint. Mutually exclusive with the
   * Account ID.
   */
  zone_id?: string;

  /**
   * Body param: A version number identifying the current `client_secret` associated
   * with the service token. Incrementing it triggers a rotation; the previous secret
   * will still be accepted until the time indicated by
   * `previous_client_secret_expires_at`.
   */
  client_secret_version?: number;

  /**
   * Body param: The duration for how long the service token will be valid. Must be
   * in the format `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s,
   * m, h. The default is 1 year in hours (8760h).
   */
  duration?: string;

  /**
   * Body param: The expiration of the previous `client_secret`. This can be modified
   * at any point after a rotation. For example, you may extend it further into the
   * future if you need more time to update services with the new secret; or move it
   * into the past to immediately invalidate the previous token in case of
   * compromise.
   */
  previous_client_secret_expires_at?: string;
}

export interface ServiceTokenUpdateParams {
  /**
   * Path param: The Account ID to use for this endpoint. Mutually exclusive with the
   * Zone ID.
   */
  account_id?: string;

  /**
   * Path param: The Zone ID to use for this endpoint. Mutually exclusive with the
   * Account ID.
   */
  zone_id?: string;

  /**
   * Body param: A version number identifying the current `client_secret` associated
   * with the service token. Incrementing it triggers a rotation; the previous secret
   * will still be accepted until the time indicated by
   * `previous_client_secret_expires_at`.
   */
  client_secret_version?: number;

  /**
   * Body param: The duration for how long the service token will be valid. Must be
   * in the format `300ms` or `2h45m`. Valid time units are: ns, us (or µs), ms, s,
   * m, h. The default is 1 year in hours (8760h).
   */
  duration?: string;

  /**
   * Body param: The name of the service token.
   */
  name?: string;

  /**
   * Body param: The expiration of the previous `client_secret`. This can be modified
   * at any point after a rotation. For example, you may extend it further into the
   * future if you need more time to update services with the new secret; or move it
   * into the past to immediately invalidate the previous token in case of
   * compromise.
   */
  previous_client_secret_expires_at?: string;
}

export interface ServiceTokenListParams extends V4PagePaginationArrayParams {
  /**
   * Path param: The Account ID to use for this endpoint. Mutually exclusive with the
   * Zone ID.
   */
  account_id?: string;

  /**
   * Path param: The Zone ID to use for this endpoint. Mutually exclusive with the
   * Account ID.
   */
  zone_id?: string;

  /**
   * Query param: The name of the service token.
   */
  name?: string;

  /**
   * Query param: Search for service tokens by other listed query parameters.
   */
  search?: string;
}

export interface ServiceTokenDeleteParams {
  /**
   * The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.
   */
  account_id?: string;

  /**
   * The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.
   */
  zone_id?: string;
}

export interface ServiceTokenGetParams {
  /**
   * The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.
   */
  account_id?: string;

  /**
   * The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.
   */
  zone_id?: string;
}

export interface ServiceTokenRefreshParams {
  /**
   * Identifier.
   */
  account_id?: string;
}

export interface ServiceTokenRotateParams {
  /**
   * Path param: Identifier.
   */
  account_id?: string;

  /**
   * Body param: The expiration of the previous `client_secret`. If not provided, it
   * defaults to the current timestamp in order to immediately expire the previous
   * secret.
   */
  previous_client_secret_expires_at?: string;
}

ServiceTokens.ServiceTokensV4PagePaginationArray = ServiceTokensV4PagePaginationArray;

export declare namespace ServiceTokens {
  export {
    type ServiceToken as ServiceToken,
    type ServiceTokenCreateResponse as ServiceTokenCreateResponse,
    type ServiceTokenRotateResponse as ServiceTokenRotateResponse,
    ServiceTokensV4PagePaginationArray as ServiceTokensV4PagePaginationArray,
    type ServiceTokenCreateParams as ServiceTokenCreateParams,
    type ServiceTokenUpdateParams as ServiceTokenUpdateParams,
    type ServiceTokenListParams as ServiceTokenListParams,
    type ServiceTokenDeleteParams as ServiceTokenDeleteParams,
    type ServiceTokenGetParams as ServiceTokenGetParams,
    type ServiceTokenRefreshParams as ServiceTokenRefreshParams,
    type ServiceTokenRotateParams as ServiceTokenRotateParams,
  };
}
