import { Session as Session$1, User as User$1 } from "../../types/models.mjs";
import { AccessControl, Role } from "../access/types.mjs";
import { Invitation, Member, Organization, OrganizationRole, Team, TeamMember } from "./schema.mjs";
import { AuthContext, Awaitable, GenericEndpointContext } from "@better-auth/core";
import { DBFieldAttribute } from "@better-auth/core/db";

//#region src/plugins/organization/types.d.ts
interface OrganizationOptions {
  /**
   * Configure whether new users are able to create new organizations.
   * You can also pass a function that returns a boolean.
   *
   * 	@example
   * ```ts
   * allowUserToCreateOrganization: async (user) => {
   * 		const plan = await getUserPlan(user);
   *      return plan.name === "pro";
   * }
   * ```
   * @default true
   */
  allowUserToCreateOrganization?: (boolean | ((user: User$1 & Record<string, any>) => Awaitable<boolean>)) | undefined;
  /**
   * The maximum number of organizations a user can create.
   *
   * You can also pass a function that returns a boolean. The function should return `true` if the user has reached their organization limit, and `false` otherwise.
   *
   * @default unlimited
   * @example
   * ```ts
   * organizationLimit: async (user) => {
   *   const plan = await getUserPlan(user);
   *   // Return true if the user has reached their organization limit, false otherwise
   *   return plan.name === "pro";
   * }
   * ```
   */
  organizationLimit?: (number | ((user: User$1 & Record<string, any>) => Awaitable<boolean>)) | undefined;
  /**
   * The role that is assigned to the creator of the
   * organization.
   *
   * @default "owner"
   */
  creatorRole?: string | undefined;
  /**
   * The maximum number of members allowed in an organization.
   *
   * You can also pass a function that returns the limit number
   *
   * @default 100
   */
  membershipLimit?: number | ((user: User$1, organization: Organization) => Promise<number> | number) | undefined;
  /**
   * Configure the roles and permissions for the
   * organization plugin.
   */
  ac?: AccessControl | undefined;
  /**
   * Custom permissions for roles.
   */
  roles?: { [key in string]?: Role<any> } | undefined;
  /**
   * Dynamic access control for the organization plugin.
   */
  dynamicAccessControl?: {
    /**
     * Whether to enable dynamic access control for the organization plugin.
     *
     * @default false
     */
    enabled?: boolean;
    /**
     * The maximum number of roles that can be created for an organization.
     *
     * @default Infinite
     */
    maximumRolesPerOrganization?: number | ((organizationId: string) => Awaitable<number>);
  } | undefined;
  /**
   * Support for team.
   */
  teams?: {
    /**
     * Enable team features.
     */
    enabled: boolean;
    /**
     * Default team configuration
     */
    defaultTeam?: {
      /**
       * Enable creating a default team when an organization is created
       *
       * @default true
       */
      enabled: boolean;
      /**
       * Pass a custom default team creator function
       */
      customCreateDefaultTeam?: (organization: Organization & Record<string, any>, ctx?: GenericEndpointContext) => Promise<Team & Record<string, any>>;
    };
    /**
     * Maximum number of teams an organization can have.
     *
     * You can pass a number or a function that returns a number
     *
     * @default "unlimited"
     *
     * @param organization
     * @param request
     * @returns
     */
    maximumTeams?: ((data: {
      organizationId: string;
      session: {
        user: User$1;
        session: Session$1;
      } | null;
    }, ctx?: GenericEndpointContext) => Awaitable<number>) | number;
    /**
     * The maximum number of members per team.
     *
     * if `undefined`, there is no limit.
     *
     * @default undefined
     */
    maximumMembersPerTeam?: number | ((data: {
      teamId: string;
      session: {
        user: User$1;
        session: Session$1;
      };
      organizationId: string;
    }) => Awaitable<number>) | undefined;
    /**
     * By default, if an organization does only have one team, they'll not be able to remove it.
     *
     * You can disable this behavior by setting this to `false.
     *
     * @default false
     */
    allowRemovingAllTeams?: boolean;
  };
  /**
   * The expiration time for the invitation link.
   *
   * @default 48 hours
   */
  invitationExpiresIn?: number | undefined;
  /**
   * The maximum invitation a user can send.
   *
   * @default 100
   */
  invitationLimit?: number | ((data: {
    user: User$1 & Record<string, any>;
    organization: Organization & Record<string, any>;
    member: Member & Record<string, any>;
  }, ctx: AuthContext) => Awaitable<number>) | undefined;
  /**
   * Cancel pending invitations on re-invite.
   *
   * @default false
   */
  cancelPendingInvitationsOnReInvite?: boolean | undefined;
  /**
   * Require email verification on accepting or rejecting an invitation
   *
   * @default false
   */
  requireEmailVerificationOnInvitation?: boolean | undefined;
  /**
   * Send an email with the
   * invitation link to the user.
   *
   * Note: Better Auth doesn't
   * generate invitation URLs.
   * You'll need to construct the
   * URL using the invitation ID
   * and pass it to the
   * acceptInvitation endpoint for
   * the user to accept the
   * invitation.
   *
   * @example
   * ```ts
   * sendInvitationEmail: async (data) => {
   * 	const url = `https://yourapp.com/organization/
   * accept-invitation?id=${data.id}`;
   * 	 sendEmail(data.email, "Invitation to join
   * organization", `Click the link to join the
   * organization: ${url}`);
   * }
   * ```
   */
  sendInvitationEmail?: ((data: {
    /**
     * the invitation id
     */
    id: string;
    /**
     * the role of the user
     */
    role: string;
    /**
     * the email of the user
     */
    email: string;
    /**
     * the organization the user is invited to join
     */
    organization: Organization;
    /**
     * the invitation object
     */
    invitation: Invitation;
    /**
     * the member who is inviting the user
     */
    inviter: Member & {
      user: User$1;
    };
  },
  /**
   * The request object
   */

  request?: Request) => Promise<void>) | undefined;
  /**
   * The schema for the organization plugin.
   */
  schema?: {
    session?: {
      fields?: {
        activeOrganizationId?: string;
        activeTeamId?: string;
      };
    };
    organization?: {
      modelName?: string;
      fields?: { [key in keyof Omit<Organization, "id">]?: string };
      additionalFields?: { [key in string]: DBFieldAttribute };
    };
    member?: {
      modelName?: string;
      fields?: { [key in keyof Omit<Member, "id">]?: string };
      additionalFields?: { [key in string]: DBFieldAttribute };
    };
    invitation?: {
      modelName?: string;
      fields?: { [key in keyof Omit<Invitation, "id">]?: string };
      additionalFields?: { [key in string]: DBFieldAttribute };
    };
    team?: {
      modelName?: string;
      fields?: { [key in keyof Omit<Team, "id">]?: string };
      additionalFields?: { [key in string]: DBFieldAttribute };
    };
    teamMember?: {
      modelName?: string;
      fields?: { [key in keyof Omit<TeamMember, "id">]?: string };
    };
    organizationRole?: {
      modelName?: string;
      fields?: { [key in keyof Omit<OrganizationRole, "id">]?: string };
      additionalFields?: { [key in string]: DBFieldAttribute };
    };
  } | undefined;
  /**
   * Disable organization deletion
   *
   * @default false
   */
  disableOrganizationDeletion?: boolean | undefined;
  /**
   * Hooks for organization
   */
  organizationHooks?: {
    /**
     * A callback that runs before the organization is created
     *
     * You can return a `data` object to override the default data.
     *
     * @example
     * ```ts
     * beforeCreateOrganization: async (data) => {
     * 	return {
     * 		data: {
     * 			...data.organization,
     * 		},
     * 	};
     * }
     * ```
     *
     * You can also throw `new APIError` to stop the organization creation.
     *
     * @example
     * ```ts
     * beforeCreateOrganization: async (data) => {
     * 	throw new APIError("BAD_REQUEST", {
     * 		message: "Organization creation is disabled",
     * 	});
     * }
     */
    beforeCreateOrganization?: (data: {
      organization: {
        name?: string;
        slug?: string;
        logo?: string;
        metadata?: Record<string, any>;
        [key: string]: any;
      };
      user: User$1 & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after the organization is created
     */
    afterCreateOrganization?: (data: {
      organization: Organization & Record<string, any>;
      member: Member & Record<string, any>;
      user: User$1 & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before the organization is updated
     *
     * You can return a `data` object to override the default data.
     *
     * @example
     * ```ts
     * beforeUpdateOrganization: async (data) => {
     * 	return { data: { ...data.organization } };
     * }
     */
    beforeUpdateOrganization?: (data: {
      organization: {
        name?: string;
        slug?: string;
        logo?: string;
        metadata?: Record<string, any>;
        [key: string]: any;
      };
      user: User$1 & Record<string, any>;
      member: Member & Record<string, any>;
    }) => Promise<void | {
      data: {
        name?: string;
        slug?: string;
        logo?: string;
        metadata?: Record<string, any>;
        [key: string]: any;
      };
    }>;
    /**
     * A callback that runs after the organization is updated
     *
     * @example
     * ```ts
     * afterUpdateOrganization: async (data) => {
     * 	console.log(data.organization);
     * }
     * ```
     */
    afterUpdateOrganization?: (data: {
      /**
       * Updated organization object
       *
       * This could be `null` if an adapter doesn't return updated organization.
       */
      organization: (Organization & Record<string, any>) | null;
      user: User$1 & Record<string, any>;
      member: Member & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before the organization is deleted
     */
    beforeDeleteOrganization?: (data: {
      organization: Organization & Record<string, any>;
      user: User$1 & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after the organization is deleted
     */
    afterDeleteOrganization?: (data: {
      organization: Organization & Record<string, any>;
      user: User$1 & Record<string, any>;
    }) => Promise<void>;
    /**
     * Member hooks
     */
    /**
     * A callback that runs before a member is added to an organization
     *
     * You can return a `data` object to override the default data.
     *
     * @example
     * ```ts
     * beforeAddMember: async (data) => {
     * 	return {
     * 		data: {
     * 			...data.member,
     * 			role: "custom-role"
     * 		}
     * 	};
     * }
     * ```
     */
    beforeAddMember?: (data: {
      member: {
        userId: string;
        organizationId: string;
        role: string;
        [key: string]: any;
      };
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after a member is added to an organization
     */
    afterAddMember?: (data: {
      member: Member & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a member is removed from an organization
     */
    beforeRemoveMember?: (data: {
      member: Member & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after a member is removed from an organization
     */
    afterRemoveMember?: (data: {
      member: Member & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a member's role is updated
     *
     * You can return a `data` object to override the default data.
     */
    beforeUpdateMemberRole?: (data: {
      member: Member & Record<string, any>;
      newRole: string;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: {
        role: string;
        [key: string]: any;
      };
    }>;
    /**
     * A callback that runs after a member's role is updated
     */
    afterUpdateMemberRole?: (data: {
      member: Member & Record<string, any>;
      previousRole: string;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * Invitation hooks
     */
    /**
     * A callback that runs before an invitation is created
     *
     * You can return a `data` object to override the default data.
     *
     * @example
     * ```ts
     * beforeCreateInvitation: async (data) => {
     * 	return {
     * 		data: {
     * 			...data.invitation,
     * 			expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
     * 		}
     * 	};
     * }
     * ```
     */
    beforeCreateInvitation?: (data: {
      invitation: {
        email: string;
        role: string;
        organizationId: string;
        inviterId: string;
        teamId?: string;
        [key: string]: any;
      };
      inviter: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after an invitation is created
     */
    afterCreateInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      inviter: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before an invitation is accepted
     */
    beforeAcceptInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after an invitation is accepted
     */
    afterAcceptInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      member: Member & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before an invitation is rejected
     */
    beforeRejectInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after an invitation is rejected
     */
    afterRejectInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before an invitation is cancelled
     */
    beforeCancelInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      cancelledBy: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after an invitation is cancelled
     */
    afterCancelInvitation?: (data: {
      invitation: Invitation & Record<string, any>;
      cancelledBy: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * Team hooks (when teams are enabled)
     */
    /**
     * A callback that runs before a team is created
     *
     * You can return a `data` object to override the default data.
     */
    beforeCreateTeam?: (data: {
      team: {
        name: string;
        organizationId: string;
        [key: string]: any;
      };
      user?: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after a team is created
     */
    afterCreateTeam?: (data: {
      team: Team & Record<string, any>;
      user?: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a team is updated
     *
     * You can return a `data` object to override the default data.
     */
    beforeUpdateTeam?: (data: {
      team: Team & Record<string, any>;
      updates: {
        name?: string;
        [key: string]: any;
      };
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after a team is updated
     */
    afterUpdateTeam?: (data: {
      team: (Team & Record<string, any>) | null;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a team is deleted
     */
    beforeDeleteTeam?: (data: {
      team: Team & Record<string, any>;
      user?: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after a team is deleted
     */
    afterDeleteTeam?: (data: {
      team: Team & Record<string, any>;
      user?: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a member is added to a team
     */
    beforeAddTeamMember?: (data: {
      teamMember: {
        teamId: string;
        userId: string;
        [key: string]: any;
      };
      team: Team & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void | {
      data: Record<string, any>;
    }>;
    /**
     * A callback that runs after a member is added to a team
     */
    afterAddTeamMember?: (data: {
      teamMember: TeamMember & Record<string, any>;
      team: Team & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs before a member is removed from a team
     */
    beforeRemoveTeamMember?: (data: {
      teamMember: TeamMember & Record<string, any>;
      team: Team & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
    /**
     * A callback that runs after a member is removed from a team
     */
    afterRemoveTeamMember?: (data: {
      teamMember: TeamMember & Record<string, any>;
      team: Team & Record<string, any>;
      user: User$1 & Record<string, any>;
      organization: Organization & Record<string, any>;
    }) => Promise<void>;
  } | undefined;
}
//#endregion
export { OrganizationOptions };