/**
 * API error vocabulary.
 *
 * Every failure the client can meaningfully react to has a stable machine-readable code
 * and a bilingual message. Anything else becomes a generic 500 — stack traces, database
 * errors and secrets never cross the wire (§36).
 */

export const ERROR_CODES = {
  unauthenticated: 'UNAUTHENTICATED',
  permissionDenied: 'PERMISSION_DENIED',
  notFound: 'NOT_FOUND',
  validationFailed: 'VALIDATION_FAILED',
  rateLimited: 'RATE_LIMITED',
  csrfInvalid: 'CSRF_INVALID',
  conflict: 'CONFLICT',
  accountLocked: 'ACCOUNT_LOCKED',
  invalidCredentials: 'INVALID_CREDENTIALS',
  simulationFailed: 'SIMULATION_FAILED',
  invalidScenario: 'INVALID_SCENARIO',
  duplicateSubmission: 'DUPLICATE_SUBMISSION',
  serverError: 'SERVER_ERROR',
} as const

export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES]

const STATUS_BY_CODE: Record<ErrorCode, number> = {
  UNAUTHENTICATED: 401,
  PERMISSION_DENIED: 403,
  NOT_FOUND: 404,
  VALIDATION_FAILED: 422,
  RATE_LIMITED: 429,
  CSRF_INVALID: 403,
  CONFLICT: 409,
  ACCOUNT_LOCKED: 423,
  INVALID_CREDENTIALS: 401,
  SIMULATION_FAILED: 422,
  INVALID_SCENARIO: 422,
  DUPLICATE_SUBMISSION: 409,
  SERVER_ERROR: 500,
}

export const ERROR_MESSAGES: Record<ErrorCode, { en: string; ar: string }> = {
  UNAUTHENTICATED: {
    en: 'You need to sign in to continue.',
    ar: 'يجب تسجيل الدخول للمتابعة.',
  },
  PERMISSION_DENIED: {
    en: 'Your role does not grant access to this action.',
    ar: 'دورك الحالي لا يمنحك صلاحية هذا الإجراء.',
  },
  NOT_FOUND: { en: 'The requested record was not found.', ar: 'السجل المطلوب غير موجود.' },
  VALIDATION_FAILED: {
    en: 'Some of the submitted values are not valid.',
    ar: 'بعض القيم المُرسلة غير صالحة.',
  },
  RATE_LIMITED: {
    en: 'Too many requests. Please wait a moment and try again.',
    ar: 'طلبات كثيرة جدًا. انتظر لحظة ثم أعد المحاولة.',
  },
  CSRF_INVALID: {
    en: 'Your session security token has expired. Refresh the page and try again.',
    ar: 'انتهت صلاحية رمز الأمان. أعد تحميل الصفحة وحاول مرة أخرى.',
  },
  CONFLICT: { en: 'That record has already been changed.', ar: 'تم تغيير هذا السجل بالفعل.' },
  ACCOUNT_LOCKED: {
    en: 'This account is temporarily locked after repeated failed sign-ins.',
    ar: 'تم قفل الحساب مؤقتًا بعد محاولات دخول فاشلة متكررة.',
  },
  INVALID_CREDENTIALS: {
    en: 'Email or password is incorrect.',
    ar: 'البريد الإلكتروني أو كلمة المرور غير صحيحة.',
  },
  SIMULATION_FAILED: {
    en: 'The simulation could not be completed with the supplied parameters.',
    ar: 'تعذّر إكمال المحاكاة بالمعطيات المُدخلة.',
  },
  INVALID_SCENARIO: {
    en: 'The scenario definition is incomplete or inconsistent.',
    ar: 'تعريف السيناريو غير مكتمل أو غير متسق.',
  },
  DUPLICATE_SUBMISSION: {
    en: 'This action has already been submitted.',
    ar: 'تم إرسال هذا الإجراء مسبقًا.',
  },
  SERVER_ERROR: {
    en: 'Something went wrong on our side. The incident has been logged.',
    ar: 'حدث خطأ من جانبنا، وقد تم تسجيل الحادثة.',
  },
}

export class ApiError extends Error {
  readonly code: ErrorCode
  readonly status: number
  readonly details?: unknown

  constructor(code: ErrorCode, options: { details?: unknown; message?: string } = {}) {
    super(options.message ?? ERROR_MESSAGES[code].en)
    this.name = 'ApiError'
    this.code = code
    this.status = STATUS_BY_CODE[code]
    this.details = options.details
  }
}

export const notFound = (message?: string) => new ApiError(ERROR_CODES.notFound, { message })
export const permissionDenied = () => new ApiError(ERROR_CODES.permissionDenied)
export const unauthenticated = () => new ApiError(ERROR_CODES.unauthenticated)
export const validationFailed = (details: unknown) =>
  new ApiError(ERROR_CODES.validationFailed, { details })
