-- LA CONCIERGERIE DEVIENT UNE ENTITE, ET C'EST L'ABONNE.
--
-- POURQUOI ELLE MANQUAIT. Jusqu'ici, « une conciergerie » n'existait pas : il y avait des
-- COMPTES de role concierge, et tout ce qui les concernait pendait a leur identifiant —
-- clients.concierge_id, biens.concierge_id, types_prestation.concierge_id,
-- utilisateurs.concierge_id. Deux comptes concierge etaient donc deux entreprises sans lien,
-- et la migration 005 l'inscrit noir sur blanc :
--
--     CHECK (concierge_id IS NULL OR role IN ('prestataire','proprietaire'))
--
-- un concierge ne peut pas etre rattache a un autre concierge.
--
-- CE QUI L'A RENDUE NECESSAIRE : une offre d'abonnement qui compte un nombre de CONCIERGES.
-- Ce nombre n'a de sens que s'il existe quelque chose qui peut en contenir plusieurs, et qui
-- souscrit. C'est cette table.
--
-- ================================================================================
-- CE QU'ELLE NE FAIT PAS, ET IL FAUT LE LIRE AVANT DE CONTINUER
-- ================================================================================
--
-- ELLE NE TOUCHE PAS AU PERIMETRE DE TRAVAIL. clients.concierge_id, biens.concierge_id et
-- utilisateurs.concierge_id restent ce qu'ils sont : ce que chaque concierge voit reste borne
-- a CE COMPTE-LA, exactement comme avant. PorteeBiens n'est pas modifiee, ni les trois
-- clausePortee() des depots, ni aucune des 550 assertions de tests_droits.
--
-- C'EST UN CHOIX, PAS UN RACCOURCI. Les quatre quotas se comptent tres bien depuis la
-- conciergerie sans partager quoi que ce soit :
--
--     concierges    utilisateurs WHERE conciergerie_id = X AND role = 'concierge'
--     prestataires  utilisateurs WHERE concierge_id IN (les concierges de X)
--     clients       clients      WHERE concierge_id IN (les concierges de X)
--     biens         biens        WHERE concierge_id IN (les concierges de X)
--
-- Faire partager le perimetre a deux collegues de la meme conciergerie est une DECISION
-- METIER distincte — « Marie voit-elle les clients de Paul ? » — qui ne se deduit pas du fait
-- qu'ils paient le meme abonnement. Elle pourra se prendre plus tard sans rien defaire d'ici :
-- il suffira alors de faire porter la portee sur conciergerie_id.

CREATE TABLE conciergeries (
    id         BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    reference  CHAR(26)        NOT NULL,

    -- « Conciergerie des Cimes ». Le nom de l'ENTREPRISE, qui n'est pas celui d'une personne :
    -- c'est precisement la distinction que cette table introduit.
    nom        VARCHAR(160)    NOT NULL,

    -- On ne supprime pas une conciergerie : ses abonnements successifs la referencent, et
    -- c'est l'historique de facturation. Desactiver suffit.
    actif      TINYINT(1)      NOT NULL DEFAULT 1,

    cree_le    DATETIME        NOT NULL,
    modifie_le DATETIME        NOT NULL,

    PRIMARY KEY (id),
    UNIQUE KEY uq_conciergeries_reference (reference),
    KEY idx_conciergeries_nom (actif, nom)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- LE RATTACHEMENT D'UN COMPTE CONCIERGE A SA CONCIERGERIE.
--
-- NULLABLE, ET CE N'EST PAS UN RELACHEMENT. Trois etats existent pour de bon :
--
--   un admin ou un superadmin       n'appartient a aucune conciergerie, il les administre
--                                   toutes ;
--   un prestataire, un proprietaire n'en releve pas DIRECTEMENT — il releve d'un concierge,
--                                   qui lui-meme releve d'une conciergerie. Dupliquer le lien
--                                   ici creerait deux chemins vers la meme reponse, donc deux
--                                   occasions de diverger ;
--   un concierge qu'on vient de     l'administrateur le cree, puis lui designe sa
--   creer                           conciergerie. Exiger les deux d'un coup obligerait a
--                                   inventer une entreprise pour tout compte de passage.
--
-- LE CHECK EST DONC L'INVERSE DE CELUI DE LA MIGRATION 005 : la ou concierge_id n'est permis
-- QUE pour un prestataire ou un proprietaire, conciergerie_id n'est permis QUE pour un
-- concierge. Les deux colonnes ne peuvent pas etre remplies sur la meme ligne, et c'est ce qui
-- garantit qu'il n'y a jamais deux chemins vers la conciergerie d'un compte.
ALTER TABLE utilisateurs
    ADD COLUMN conciergerie_id BIGINT UNSIGNED NULL AFTER concierge_id,
    ADD KEY idx_utilisateurs_conciergerie (conciergerie_id, role, actif),
    ADD CONSTRAINT fk_utilisateurs_conciergerie
        FOREIGN KEY (conciergerie_id) REFERENCES conciergeries (id) ON DELETE RESTRICT,
    ADD CONSTRAINT ck_utilisateurs_conciergerie
        CHECK (conciergerie_id IS NULL OR role = 'concierge');

-- CHAQUE CONCIERGE EXISTANT RECOIT SA PROPRE CONCIERGERIE, une par compte.
--
-- C'EST L'ETAT LE PLUS FIDELE A CE QUI EXISTE : aujourd'hui deux comptes concierge sont deux
-- entreprises sans lien, et les regrouper d'office inventerait une structure que personne n'a
-- decrite. Un administrateur regroupera ensuite ceux qui vont ensemble, ce qui est un geste
-- qu'on peut faire en connaissance de cause — l'inverse, separer ce qu'on aurait fusionne a
-- tort, demanderait de savoir qui possedait quoi.
--
-- LE NOM REPREND CELUI DU COMPTE, faute de mieux : c'est ce qu'un administrateur reconnaitra
-- dans une liste, et il le corrigera en deux clics.
--
-- LA REFERENCE EST UN ULID FABRIQUE EN SQL. Ulid::generer() vit en PHP et n'est pas atteignable
-- ici. On produit donc 26 caracteres a partir de l'identifiant du compte : treize zeros, puis
-- l'identifiant en hexadecimal. L'unicite est la seule propriete exigee, et elle decoule de
-- celle de u.id.
--
-- L'ALPHABET N'EST PAS LIBRE, ET C'EST LE PIEGE DE CETTE MIGRATION.
--
-- Ulid::valide() controle « ^[0-9A-HJKMNP-TV-Z]{26}$ » : l'alphabet de Crockford, qui EXCLUT
-- I, L, O et U — les quatre lettres qui se confondent avec 1 et 0 a la lecture. Une reference
-- lisible comme « 0MIGRATION034... » aurait donc ete refusee par le validateur, et
-- trouverParReference() aurait rendu null pour CHAQUE conciergerie migree. Une panne totale et
-- silencieuse, sur une chaine qui a l'air parfaitement inoffensive.
--
-- L'hexadecimal (0-9, A-F) est un sous-ensemble strict de cet alphabet : il ne peut pas se
-- tromper.
--
-- Ces references ne sont pas triables par date de creation, contrairement a de vrais ULID.
-- Aucun ecran ne s'y fie : le tri se fait sur le nom.
INSERT INTO conciergeries (reference, nom, actif, cree_le, modifie_le)
SELECT
    CONCAT(REPEAT('0', 13), LPAD(UPPER(HEX(u.id)), 13, '0')),
    u.nom,
    u.actif,
    NOW(),
    NOW()
  FROM utilisateurs u
 WHERE u.role = 'concierge';

UPDATE utilisateurs u
  JOIN conciergeries c
    ON c.reference = CONCAT(REPEAT('0', 13), LPAD(UPPER(HEX(u.id)), 13, '0'))
   SET u.conciergerie_id = c.id,
       u.modifie_le      = NOW()
 WHERE u.role = 'concierge';
