/**
 * SSO 错误码 → i18n key 路径映射
 *
 * 与后端 `backend/src/modules/organization/auth/sso/sso-errors.ts` 的 `SsoErrorCode`
 * 必须保持同步。后端新增/重命名错误码时，TS `Record<SsoErrorCode, string>` exhaustive
 * 校验会立即报错（缺成员或多余成员），避免静默漂移。
 *
 * 事实源：docs/modules/organization/05-ui-interaction-spec.md「错误状态（v2.4 新增 · SSO 错误码）」
 *
 * 注意：`IAM_USER_SUSPENDED` 走现有错误码，**不**在后端 `SsoErrorCode` enum 中，
 * 但前端 toast 仍需要映射，故在 union 末尾单独列出。
 */
export type SsoErrorCode =
  | 'SSO_DOMAIN_NOT_ALLOWED'
  | 'SSO_TOKEN_INVALID'
  | 'SSO_EMAIL_MISSING'
  | 'SSO_BINDING_CONFLICT'
  | 'SSO_PROVIDER_UNAVAILABLE'
  | 'SSO_USER_CANCELLED'
  | 'SSO_CONSENT_REQUIRED'
  | 'SSO_PROVIDER_REJECTED'
  | 'IAM_USER_SUSPENDED';

export const SSO_ERROR_CODE_TO_I18N_KEY: Record<SsoErrorCode, string> = {
  SSO_DOMAIN_NOT_ALLOWED: 'auth.sso.error.domainNotAllowed',
  SSO_TOKEN_INVALID: 'auth.sso.error.tokenInvalid',
  SSO_EMAIL_MISSING: 'auth.sso.error.emailMissing',
  SSO_BINDING_CONFLICT: 'auth.sso.error.bindingConflict',
  SSO_PROVIDER_UNAVAILABLE: 'auth.sso.error.providerUnavailable',
  SSO_USER_CANCELLED: 'auth.sso.error.userCancelled',
  SSO_CONSENT_REQUIRED: 'auth.sso.error.consentRequired',
  SSO_PROVIDER_REJECTED: 'auth.sso.error.providerRejected',
  IAM_USER_SUSPENDED: 'auth.sso.error.iamUserSuspended',
};

/**
 * 把后端错误码解析为 i18n key 路径（点分）；未知值兜底走 `auth.sso.error.fallback`。
 *
 * 调用方拿到 key 后用 `lookupTranslation(t, key)` 取实际字符串。
 */
export function resolveSsoErrorI18nKey(code: string | null | undefined): string {
  if (code && code in SSO_ERROR_CODE_TO_I18N_KEY) {
    return SSO_ERROR_CODE_TO_I18N_KEY[code as SsoErrorCode];
  }
  return 'auth.sso.error.fallback';
}

/**
 * 按点分路径在 i18n bundle 中取字符串，缺失返回 undefined。
 *
 * 示例：lookupTranslation(t, 'auth.sso.error.domainNotAllowed')
 *      → t.auth.sso.error.domainNotAllowed
 */
export function lookupTranslation(
  bundle: unknown,
  path: string,
): string | undefined {
  const parts = path.split('.');
  let cursor: any = bundle;
  for (const part of parts) {
    if (cursor == null || typeof cursor !== 'object') return undefined;
    cursor = cursor[part];
  }
  return typeof cursor === 'string' ? cursor : undefined;
}
