<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Database;

/**
 * Miroir SQL de `CategoryCodeGenerator::slugify()` (module Catalog, ERP-78).
 *
 * Le `code` d'une `Category` est un slug MAJUSCULE deterministe du nom. A
 * l'execution (POST/PATCH API), il est genere en PHP par `CategoryCodeGenerator`
 * via `AsciiSlugger`. Mais la migration corrective `Version20260602100000` doit
 * backfiller le `code` des categories pre-existantes en SQL pur (le backfill
 * tourne dans le plan `addSql`, sans acces aux services applicatifs).
 *
 * Deux implementations d'un meme slug = risque de derive : un nom accentue
 * comme « Independant » doit produire le MEME code (`INDEPENDANT`) quel que soit
 * le chemin. Cette classe est la SOURCE UNIQUE de l'expression SQL ; son egalite
 * avec le générateur PHP est verrouillee par `CategoryCodeSqlSlugTest`.
 *
 * Domaine couvert : noms francais / Latin-1 (tous les accents, minuscule +
 * majuscule, translitteres vers l'ASCII comme le fait `AsciiSlugger`). Limite
 * connue et assumee : les ligatures (`Œ`->`OE`, `ß`->`SS`) ne sont PAS gerees
 * par `translate()` (mapping 1->1 uniquement) ; elles n'apparaissent pas dans
 * les noms de categories CLIENT et le backfill ne s'execute de toute facon que
 * sur des bases dev deja peuplees (en prod la table `category` est vide).
 */
final class CategoryCodeSql
{
    /** Longueur maximale de la colonne `category.code` (cf. CategoryCodeGenerator). */
    private const int MAX_LENGTH = 50;

    /**
     * Accents Latin-1 (minuscules puis majuscules) translitteres vers leur
     * equivalent ASCII minuscule — `UPPER()` repasse tout en majuscule ensuite.
     * `translate()` mappe caractere a caractere : `ACCENT_FROM` et `ACCENT_TO`
     * doivent avoir EXACTEMENT le meme nombre de caracteres.
     */
    private const string ACCENT_FROM = 'àâäáãåçéèêëíìîïñóòôöõúùûüýÿÀÂÄÁÃÅÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜÝŸ';
    private const string ACCENT_TO   = 'aaaaaaceeeeiiiinooooouuuuyyaaaaaaceeeeiiiinooooouuuuyy';

    /**
     * Expression SQL produisant le slug du `$column` donne (ex: `name`, `c.name`).
     * Reproduit fidelement `CategoryCodeGenerator::slugify` : translitteration des
     * accents, separateurs non alphanumeriques reduits a `_`, MAJUSCULE, borne a
     * 50, `_` de bord retires, fallback `CATEGORY` si vide.
     */
    public static function slugExpression(string $column): string
    {
        return sprintf(
            "COALESCE(NULLIF(TRIM(BOTH '_' FROM "
            ."LEFT(UPPER(REGEXP_REPLACE(translate(%s, '%s', '%s'), '[^A-Za-z0-9]+', '_', 'g')), %d)"
            ."), ''), 'CATEGORY')",
            $column,
            self::ACCENT_FROM,
            self::ACCENT_TO,
            self::MAX_LENGTH,
        );
    }
}
