// Map transport/bridge errors to localized human copy. The bridge surfaces
// Telegram-side failures as mautrix RespError JSON ({errcode, error}) — the
// interesting Telegram error names (FLOOD_WAIT, PHONE_NUMBER_INVALID, …)
// arrive embedded in the message text, so substring matching is the
// authoritative option short of forking the bridge.

import { ProvisioningError } from './provisioning';
import type { T } from './i18n';

export const describeApiError = (err: unknown, t: T): string => {
  if (err instanceof ProvisioningError) {
    const text = `${err.errcode ?? ''} ${err.message}`;
    if (text.includes('FLOOD_WAIT') || text.includes('FLOOD_PREMIUM_WAIT')) {
      return t('error.flood');
    }
    if (text.includes('PHONE_NUMBER_INVALID') || text.includes('PHONE_NUMBER_UNOCCUPIED')) {
      return t('error.phone-invalid');
    }
    if (text.includes('PHONE_NUMBER_BANNED')) return t('error.phone-banned');
    if (err.errcode === 'FI.MAU.BRIDGE.LOGIN_TIMED_OUT') return t('error.login-timeout');
    if (err.errcode === 'FI.MAU.BRIDGE.LOGIN_CANCELLED') return t('error.login-restart');
    // The login step machine advanced without us (a re-poll raced a state
    // change, e.g. a background 2FA scan) — desynced beyond recovery.
    if (err.errcode === 'M_BAD_STATE') return t('error.login-restart');
    if (err.errcode === 'FI.MAU.BRIDGE.TOO_MANY_LOGINS') return t('error.too-many-logins');
    // Login process evaporated server-side (bridge deletes it on errors and
    // after its 30-minute deadline) — the only recovery is starting over.
    if (err.httpStatus === 404) return t('error.login-restart');
    if (
      err.errcode === 'M_MISSING_TOKEN' ||
      err.errcode === 'M_UNKNOWN_TOKEN' ||
      err.errcode === 'M_FORBIDDEN'
    ) {
      return t('error.auth');
    }
    return t('error.generic', { reason: err.message });
  }
  // Host refused to issue OpenID creds — an operator-side config gap
  // (missing `vojo.openid` capability), not a transient failure; say so.
  if (err instanceof Error && err.message.includes('blocked by host')) {
    return t('error.openid-blocked');
  }
  if (err instanceof Error && err.message.includes('OpenID')) return t('error.auth');
  // fetch() network failures surface as TypeError; transport timeouts abort
  // with AbortError (DOMException, also instanceof Error with name).
  if (err instanceof Error && (err.name === 'TypeError' || err.name === 'AbortError')) {
    return t('error.network');
  }
  return t('error.generic', { reason: err instanceof Error ? err.message : String(err) });
};
