/**
 * Auth domain — phone-OTP login, revocable refresh-token sessions, `/me`, and public
 * role selection. Shapes mirror the b2 contract
 * (`dev/contracts/domains/identity-auth.md` + `dev/contracts/openapi/swagger.v1.json`)
 * exactly, including the **camelCase** wire casing confirmed against the live envelope.
 *
 * Enums cross the wire as stable string codes (money-and-types.md) and are mirrored here
 * as string-literal unions — never hardcode a display label off a code (labels are i18n keys).
 */

/** Publicly self-selectable roles (customer and nurse may coexist). */
export type PublicRole = 'customer' | 'nurse';

/** Internal-only admin sub-roles — never self-assignable (`me/select_role` → 403). */
export type AdminRole = 'admin' | 'support' | 'finance' | 'moderation' | 'super_admin';

/** Any role code the server may report on a session. */
export type RoleCode = PublicRole | AdminRole;

/** Load-bearing for same-gender matching; null until the profile flow (b3) sets it. */
export type Gender = 'male' | 'female';

/** Nurse verification stage. `not_started` until the b6 pipeline exists. */
export type NurseVerificationStatus =
  | 'not_started'
  | 'in_progress'
  | 'pending_review'
  | 'verified'
  | 'rejected';

/** `POST auth/request_otp` body. The server accepts +98/0098/Persian digits and normalizes. */
export interface OtpRequest {
  phone: string;
}

/** `POST auth/request_otp` payload. Inside the resend window `otpSent` is false with the remaining seconds. */
export interface RequestOtpResult {
  otpSent: boolean;
  resendAvailableInSeconds: number;
}

/** `POST auth/verify_otp` body. */
export interface OtpVerify {
  phone: string;
  code: string;
  deviceInfo?: string;
}

/** `POST auth/refresh` body — the refresh token is itself the credential. */
export interface RefreshRequest {
  refreshToken: string;
  deviceInfo?: string;
}

/** `POST auth/logout` body. Omitting `refreshToken` (or `everywhere: true`) revokes every session. */
export interface LogoutRequest {
  refreshToken?: string;
  everywhere?: boolean;
}

/** `AuthTokensResult` — returned by verify_otp and refresh. */
export interface AuthTokens {
  accessToken: string;
  refreshToken: string;
  accessExpiresAt: string;
  refreshExpiresAt: string;
  /** `true` only on the first successful verify for a phone ⇒ send to role selection. */
  isNewUser: boolean;
  /** Active roles; empty ⇒ route the user to role selection. */
  roles: RoleCode[];
}

/** `POST me/select_role` body. Only public roles are accepted. */
export interface SelectRoleDto {
  role: PublicRole;
}

/** `MeResult` — the role router's input and the shell's role source. */
export interface Me {
  id: number;
  /** Always masked by the server (`0912*****33`); the full number is never returned. */
  phone: string;
  firstName: string | null;
  lastName: string | null;
  gender: Gender | null;
  isActive: boolean;
  roles: RoleCode[];
  hasCustomerProfile: boolean;
  hasNurseProfile: boolean;
  nurseVerificationStatus: NurseVerificationStatus;
}

/**
 * The auth domain's API seam. The real HTTP client and the in-memory mock both implement
 * this interface; selection is by config (`USE_AUTH_MOCK`), never scattered `if (mock)` checks.
 */
export interface AuthApi {
  requestOtp(body: OtpRequest): Promise<RequestOtpResult>;
  verifyOtp(body: OtpVerify): Promise<AuthTokens>;
  refresh(body: RefreshRequest): Promise<AuthTokens>;
  logout(body?: LogoutRequest): Promise<void>;
  getMe(): Promise<Me>;
  selectRole(body: SelectRoleDto): Promise<Me>;
}
