/**
 * Translates raw backend error messages (Symfony, Doctrine, API Platform)
 * into user-friendly French messages for display in toasts/alerts.
 */

const EXACT_MATCHES: Record<string, string> = {
  // UniqueConstraintSubscriber (HTTP 409)
  'nom duplique': 'Un élément avec ce nom existe déjà.',

  // English backend messages → French
  'Machine not found.': 'Machine introuvable.',
  'Composant not found.': 'Composant introuvable.',
  'Piece not found.': 'Pièce introuvable.',
  'Product not found.': 'Produit introuvable.',
  'Site not found.': 'Site introuvable.',
  'Custom field not found.': 'Champ personnalisé introuvable.',
  'Custom field value not found.': 'Valeur du champ personnalisé introuvable.',
  'Document not found.': 'Document introuvable.',
  'File not found on disk.': 'Le fichier n\'a pas été trouvé sur le serveur.',
  'Invalid document data.': 'Les données du document sont invalides.',
  'Invalid JSON payload.': 'Les données envoyées sont invalides.',
  'Unsupported entity type.': 'Type d\'entité non supporté.',
  'Entity target is missing.': 'La cible de l\'entité est manquante.',
  'customFieldId or customFieldName is required.': 'L\'identifiant du champ personnalisé est requis.',

  // Symfony validator messages
  'This value should not be blank.': 'Ce champ ne peut pas être vide.',
  'This value is not a valid email address.': 'L\'adresse email n\'est pas valide.',
  'This value is already used.': 'Cette valeur est déjà utilisée.',
  'This field is missing.': 'Un champ obligatoire est manquant.',

  // HTTP status texts (used in "Erreur XXX: StatusText" fallback)
  'Internal Server Error': 'Erreur interne du serveur. Veuillez réessayer.',
  'Bad Request': 'Requête invalide.',
  'Not Found': 'Ressource introuvable.',
  'Conflict': 'Un élément similaire existe déjà.',
  'Unprocessable Entity': 'Données invalides.',
  'Unprocessable Content': 'Données invalides.',
  'Service Unavailable': 'Service temporairement indisponible. Veuillez réessayer.',
  'Gateway Timeout': 'Le serveur met trop de temps à répondre. Veuillez réessayer.',
}

const TECHNICAL_PATTERNS: Array<[RegExp, string]> = [
  // Database / Doctrine errors
  [/SQLSTATE\[/i, 'Une erreur est survenue. Veuillez réessayer.'],
  [/An exception occurred/i, 'Une erreur est survenue. Veuillez réessayer.'],
  [/Duplicate entry/i, 'Un élément avec ces données existe déjà.'],
  [/unique.*constraint.*violation/i, 'Un élément avec ces données existe déjà.'],
  [/foreign key constraint/i, 'Impossible de supprimer cet élément car il est utilisé ailleurs.'],
  [/violates not-null constraint/i, 'Un champ obligatoire n\'a pas été renseigné.'],
  [/violates check constraint/i, 'Une valeur saisie est invalide.'],

  // Symfony / API Platform internal messages
  [/Expected argument of type/i, 'Les données envoyées sont invalides.'],
  [/Could not denormalize/i, 'Les données envoyées sont invalides.'],
  [/The JSON value could not be decoded/i, 'Les données envoyées sont invalides.'],
  [/Syntax error.*JSON/i, 'Les données envoyées sont invalides.'],
  [/No route found/i, 'Ressource introuvable.'],
  [/Access Denied/i, 'Permissions insuffisantes pour cette action.'],
]

/**
 * Detects if a message contains technical jargon that should not be shown to users.
 */
function containsTechnicalJargon(message: string): boolean {
  const patterns = [
    /stack trace/i,
    /exception/i,
    /\bat\s+[\w\\]+::/,
    /vendor\//,
    /\.php/,
    /doctrine/i,
    /symfony/i,
    /SQLSTATE/i,
    /PDOException/i,
    /DBALException/i,
    /RuntimeException/i,
    /TypeError/i,
    /LogicException/i,
    /InvalidArgumentException/i,
    /UnexpectedValueException/i,
    /constraint.*violation/i,
    /entity.*manager/i,
    /Hydra error/i,
  ]
  return patterns.some((p) => p.test(message))
}

/**
 * Translates a raw backend error message into a user-friendly French message.
 *
 * Usage:
 *   import { humanizeError } from '~/shared/utils/errorMessages'
 *   showError(humanizeError(rawMessage))
 */
export function humanizeError(rawMessage: string | undefined | null): string {
  if (!rawMessage) return 'Une erreur est survenue.'

  const trimmed = rawMessage.trim()
  if (!trimmed) return 'Une erreur est survenue.'

  // 1. Exact match
  if (EXACT_MATCHES[trimmed]) return EXACT_MATCHES[trimmed]

  // 2. "Erreur XXX: StatusText" pattern — translate the status text
  const httpMatch = trimmed.match(/^Erreur (\d{3})\s*:\s*(.+)$/)
  if (httpMatch) {
    const statusText = httpMatch[2]!.trim()
    if (EXACT_MATCHES[statusText]) return EXACT_MATCHES[statusText]
    return `Erreur serveur (${httpMatch[1]}). Veuillez réessayer.`
  }

  // 3. Regex patterns for technical errors
  for (const [pattern, replacement] of TECHNICAL_PATTERNS) {
    if (pattern.test(trimmed)) return replacement
  }

  // 4. If it contains technical jargon, replace with generic message
  if (containsTechnicalJargon(trimmed)) {
    return 'Une erreur est survenue. Veuillez réessayer.'
  }

  // 5. Already user-friendly — return as-is
  return trimmed
}

/**
 * Extracts the best error message from various backend response formats.
 * Handles: { message }, { error }, { detail }, { "hydra:description" }
 */
export function extractApiErrorMessage(errorData: Record<string, unknown>): string | null {
  if (!errorData || typeof errorData !== 'object') return null

  // Symfony validator violations — priorité max (message propre sans préfixe champ)
  if (Array.isArray(errorData.violations) && errorData.violations.length > 0) {
    const first = errorData.violations[0] as Record<string, unknown>
    if (typeof first?.message === 'string') return first.message
  }

  // UniqueConstraintSubscriber format ({ success: false, error: "nom duplique" })
  if (typeof errorData.error === 'string') return errorData.error

  // Custom controllers format
  if (typeof errorData.message === 'string') return errorData.message
  if (Array.isArray(errorData.message) && typeof errorData.message[0] === 'string') return errorData.message[0]

  // API Platform hydra format (fallback — peut contenir "propertyPath: message")
  if (typeof errorData['hydra:description'] === 'string') return errorData['hydra:description']
  if (typeof errorData.detail === 'string') return errorData.detail

  return null
}
