import { APIResource } from '../../core/resource';
import * as OrganizationAPI from './organization';
import { APIPromise } from '../../core/api-promise';
import { Page, type PageParams, PagePromise } from '../../core/pagination';
import { RequestOptions } from '../../internal/request-options';
import { startApiCallSpan } from '../../internal/tracing';
import { path } from '../../internal/utils/path';

export class Invites extends APIResource {
  /**
   * Invite a user to join the organization by email.
   *
   * On plans that draw members from a finite pool of purchased seats, the invite
   * automatically consumes a seat from the lowest tier with availability; there is
   * no seat-tier parameter. When no seat is free the request fails with a 400 error
   * rather than purchasing a seat.
   *
   * @example
   * ```ts
   * const organizationInvite =
   *   await client.organization.invites.create({
   *     email: 'user@emaildomain.com',
   *     role: 'user',
   *   });
   * ```
   */
  create(body: InviteCreateParams, options?: RequestOptions): APIPromise<OrganizationInvite> {
    return this._client.post('/v1/organizations/invites', {
      body,
      ...options,
      __span: startApiCallSpan(this._client, 'anthropic.organization.invites.create', options, {
        route: '/v1/organizations/invites',
        createdIDAttribute: 'anthropic.organization.invite.id',
      }),
    });
  }

  /**
   * Retrieve an invite by ID.
   *
   * @example
   * ```ts
   * const organizationInvite =
   *   await client.organization.invites.retrieve('invite_id');
   * ```
   */
  retrieve(inviteID: string, options?: RequestOptions): APIPromise<OrganizationInvite> {
    return this._client.get(path`/v1/organizations/invites/${inviteID}`, {
      ...options,
      __span: startApiCallSpan(this._client, 'anthropic.organization.invites.retrieve', options, {
        route: '/v1/organizations/invites/{invite_id}',
        attributes: { 'anthropic.organization.invite.id': inviteID },
      }),
    });
  }

  /**
   * List the organization's invites.
   *
   * @example
   * ```ts
   * // Automatically fetches more pages as needed.
   * for await (const organizationInvite of client.organization.invites.list()) {
   *   // ...
   * }
   * ```
   */
  list(
    query: InviteListParams | null | undefined = {},
    options?: RequestOptions,
  ): PagePromise<OrganizationInvitesPage, OrganizationInvite> {
    return this._client.getAPIList('/v1/organizations/invites', Page<OrganizationInvite>, {
      query,
      ...options,
      __span: startApiCallSpan(this._client, 'anthropic.organization.invites.list', options, {
        route: '/v1/organizations/invites',
        queryParams: ['after_id', 'before_id', 'email', 'limit', 'roles', 'statuses'],
      }),
    });
  }

  /**
   * Delete a pending invite.
   *
   * @example
   * ```ts
   * const invite = await client.organization.invites.delete(
   *   'invite_id',
   * );
   * ```
   */
  delete(inviteID: string, options?: RequestOptions): APIPromise<InviteDeleteResponse> {
    return this._client.delete(path`/v1/organizations/invites/${inviteID}`, {
      ...options,
      __span: startApiCallSpan(this._client, 'anthropic.organization.invites.delete', options, {
        route: '/v1/organizations/invites/{invite_id}',
        attributes: { 'anthropic.organization.invite.id': inviteID },
      }),
    });
  }
}

export type OrganizationInvitesPage = Page<OrganizationInvite>;

export interface OrganizationInvite {
  /**
   * ID of the Invite.
   */
  id: string;

  /**
   * RFC 3339 datetime string indicating when the Invite was accepted, or null.
   */
  accepted_at: string | null;

  /**
   * Email of the User being invited.
   */
  email: string;

  /**
   * RFC 3339 datetime string indicating when the Invite expires.
   */
  expires_at: string;

  /**
   * RFC 3339 datetime string indicating when the Invite was created.
   */
  invited_at: string;

  /**
   * RBAC group IDs recorded on the Invite (Claude Enterprise organizations), to be
   * assigned to the User when the Invite is accepted. `[]` when none.
   */
  rbac_group_ids: Array<string>;

  /**
   * Organization role of the User.
   */
  role: OrganizationAPI.OrganizationRole;

  /**
   * Status of the Invite.
   */
  status: 'accepted' | 'deleted' | 'expired' | 'pending';

  /**
   * Object type.
   *
   * For Invites, this is always `"invite"`.
   */
  type: 'invite';
}

export interface InviteDeleteResponse {
  /**
   * ID of the Invite.
   */
  id: string;

  /**
   * Deleted object type.
   *
   * For Invites, this is always `"invite_deleted"`.
   */
  type: 'invite_deleted';
}

export interface InviteCreateParams {
  /**
   * Email of the User.
   */
  email: string;

  /**
   * Role for the invited User.
   *
   * The accepted values depend on the organization type. Console and API
   * organizations accept `user`, `developer`, `billing`, and `claude_code_user`;
   * `admin` cannot be assigned through the API. Claude Enterprise organizations
   * accept `user` and `managed`; inviting with the `managed` role requires the
   * `write:rbac_groups` scope in addition to `write:members`.
   */
  role: 'billing' | 'claude_code_user' | 'developer' | 'managed' | 'user';

  /**
   * RBAC group IDs to assign to the User when the Invite is accepted. A non-empty
   * array is accepted only for a Claude Enterprise organization with RBAC groups,
   * and requires the key to carry the `write:rbac_groups` scope.
   */
  rbac_group_ids?: Array<string>;
}

export interface InviteListParams extends PageParams {
  /**
   * Filter by the email address the Invite was sent to. Matches the same way as the
   * Users list's `email` filter (normalized, case-insensitive).
   */
  email?: string;

  /**
   * Filter to items whose `role` equals one of the supplied values. Repeatable;
   * values are OR'ed together.
   *
   * Accepted values depend on the organization type: Console and API organizations
   * accept `user`, `developer`, `billing`, `admin`, and `claude_code_user`; Claude
   * Enterprise organizations accept `user`, `owner`, `primary_owner`,
   * `membership_admin`, and `managed`.
   */
  roles?: Array<string>;

  /**
   * Filter by Invite status. Repeatable; values are OR'ed together. Omit to return
   * `pending`, `accepted`, and `expired` Invites alike.
   */
  statuses?: Array<'accepted' | 'expired' | 'pending'>;
}

export declare namespace Invites {
  export {
    type OrganizationInvite as OrganizationInvite,
    type InviteDeleteResponse as InviteDeleteResponse,
    type OrganizationInvitesPage as OrganizationInvitesPage,
    type InviteCreateParams as InviteCreateParams,
    type InviteListParams as InviteListParams,
  };
}
