-- =====================================================================
--  ESQUEMA — wd_membresia lista para recibir la réplica del padrón
--
--  Proyecto : CL032BACK (Reservaciones en Línea)
--  Base     : cl032reservacionenlinea
--  Maestro  : CL001PORTALPUBLICO, base `asturias_api`, tabla wd_membresia
--
--  ---------------------------------------------------------------------
--  ANTES DE EJECUTAR
--  ---------------------------------------------------------------------
--  1. DDL: usuario ADMINISTRADOR.
--
--  2. Respaldo previo. ESTE NO ES OPCIONAL AQUÍ:
--       mysqldump -u <ADMIN> -p cl032reservacionenlinea wd_membresia \
--         > /var/backups/cl032_wd_membresia_$(date +%F).sql
--
--     wd_membresia.idMembresia NO es un número de fila: es la identidad
--     autenticable del socio (Membresia usa HasApiTokens, así que cuelga de
--     personal_access_tokens.tokenable_id) y la llave foránea de
--     rsv_notificacion y rsv_socioverificacion. Perder o renumerar esta tabla
--     cierra la sesión de todos los socios conectados.
--
--  3. Ejecución:
--       mysql -u <ADMIN> -p cl032reservacionenlinea < 2026_08_25_000001_replica_padron_membresias.sql
--
--  ES RE-EJECUTABLE: cada bloque consulta information_schema antes de actuar.
--  MySQL no tiene ADD COLUMN/INDEX IF NOT EXISTS.
--
--  ---------------------------------------------------------------------
--  QUÉ HACE
--  ---------------------------------------------------------------------
--   §1  membresiaBloqueosReservaciones, si falta
--   §2  índice por membresiaNo      (lo usa el canal de reservaciones)
--   §3  índice por idIdentificador  (lo usa el canal de invitados)
--   §4  verificación y diagnóstico de duplicados
--
--  ---------------------------------------------------------------------
--  LO QUE ESTE SCRIPT **NO** HACE, A PROPÓSITO
--  ---------------------------------------------------------------------
--  · NO borra ni vacía nada. La réplica es un UPSERT por idMembresia; un
--    TRUNCATE + recarga es justamente lo que se viene a eliminar.
--  · NO crea columnas de cola (membresiaTransferenciaReserva y su fecha).
--    Ésas viven SÓLO en el maestro: es él quien sabe qué falta por entregar.
--    Este lado no lleva cola, sólo recibe.
--  · NO pone UNIQUE en membresiaNo. Ver §4: si hoy hubiera duplicados, el
--    ALTER fallaría a mitad y dejaría la tabla a medias. Primero se mira, y
--    si el conteo sale en cero se aplica el UNIQUE comentado al final.
-- =====================================================================

SET @bd := DATABASE();


-- =====================================================================
--  §0. ESTADO ACTUAL
-- =====================================================================
SELECT
    (SELECT COUNT(*) FROM information_schema.COLUMNS
      WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
        AND COLUMN_NAME = 'membresiaBloqueosReservaciones')  AS col_bloqueos,
    (SELECT COUNT(*) FROM information_schema.STATISTICS
      WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
        AND INDEX_NAME = 'idx_membresia_no')                 AS idx_no,
    (SELECT COUNT(*) FROM information_schema.STATISTICS
      WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
        AND INDEX_NAME = 'idx_membresia_identificador')      AS idx_ident;


-- =====================================================================
--  §1. membresiaBloqueosReservaciones
-- =====================================================================
-- Áreas que le cierran al socio las reservaciones en línea. Llega desde el
-- maestro como JSON: ["General","Invitados","Reservaciones"], y "[]" cuando no
-- tiene ninguna. NULL = nunca llegó el dato.
SET @existe := (
    SELECT COUNT(*) FROM information_schema.COLUMNS
     WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
       AND COLUMN_NAME = 'membresiaBloqueosReservaciones'
);

SET @sql := IF(@existe = 0,
    "ALTER TABLE `wd_membresia`
       ADD COLUMN `membresiaBloqueosReservaciones` TEXT NULL
           COMMENT 'JSON de áreas que bloquean reservar en línea. NULL = nunca llegó el dato; [] = sin bloqueos.'
           AFTER `membresiaBeneficiarios`",
    'SELECT ''membresiaBloqueosReservaciones ya existe'''
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;


-- =====================================================================
--  §2. ÍNDICE POR membresiaNo
-- =====================================================================
-- ReplicacionEntranteController resuelve CADA reservación entrante con
-- Membresia::where('membresiaNo', ...), y Membresia::buscarPorNumero() hace lo
-- mismo en cada intento de acceso del socio. La tabla sólo declara PRIMARY KEY
-- (idMembresia), así que hoy eso es un recorrido completo cada vez.
SET @existe := (
    SELECT COUNT(*) FROM information_schema.STATISTICS
     WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
       AND INDEX_NAME = 'idx_membresia_no'
);

SET @sql := IF(@existe = 0,
    "ALTER TABLE `wd_membresia` ADD INDEX `idx_membresia_no` (`membresiaNo`)",
    'SELECT ''idx_membresia_no ya existe'''
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;


-- =====================================================================
--  §3. ÍNDICE POR idIdentificador
-- =====================================================================
-- TransferenciaController::resolverMembresia() resuelve por aquí cada solicitud
-- de invitados que llega de Tlalpan.
SET @existe := (
    SELECT COUNT(*) FROM information_schema.STATISTICS
     WHERE TABLE_SCHEMA = @bd AND TABLE_NAME = 'wd_membresia'
       AND INDEX_NAME = 'idx_membresia_identificador'
);

SET @sql := IF(@existe = 0,
    "ALTER TABLE `wd_membresia` ADD INDEX `idx_membresia_identificador` (`idIdentificador`)",
    'SELECT ''idx_membresia_identificador ya existe'''
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;


-- =====================================================================
--  §4. VERIFICACIÓN Y DIAGNÓSTICO
-- =====================================================================
SELECT COUNT(*) AS filas FROM `wd_membresia`;

-- Duplicados por número de socio. DEBE SALIR VACÍO.
-- Si sale algo, la réplica no lo causa —escribe por idMembresia— pero
-- Membresia::buscarPorNumero() está resolviendo al azar entre las coincidencias
-- desde antes, y hay que limpiarlo antes de poner el UNIQUE del final.
SELECT `membresiaNo`, COUNT(*) AS repetidas,
       GROUP_CONCAT(`idMembresia` ORDER BY `idMembresia`) AS ids
  FROM `wd_membresia`
 GROUP BY `membresiaNo`
HAVING COUNT(*) > 1;

-- Duplicados por puntero a Tlalpan. TransferenciaController ya los detecta en
-- caliente y rechaza con 'membresia_discrepante'; esto los saca de una vez.
SELECT `idIdentificador`, COUNT(*) AS repetidas,
       GROUP_CONCAT(`idMembresia` ORDER BY `idMembresia`) AS ids
  FROM `wd_membresia`
 WHERE `idIdentificador` IS NOT NULL
 GROUP BY `idIdentificador`
HAVING COUNT(*) > 1;


-- =====================================================================
--  §5. UNIQUE EN membresiaNo — SOLO SI EL §4 SALIÓ LIMPIO
-- =====================================================================
-- Descomentar y ejecutar únicamente si la primera consulta de duplicados del §4
-- no devolvió ninguna fila. Convierte el índice de búsqueda en una garantía:
-- dos socios con el mismo número dejan de ser posibles.
--
-- ALTER TABLE `wd_membresia` DROP INDEX `idx_membresia_no`;
-- ALTER TABLE `wd_membresia` ADD UNIQUE INDEX `uq_membresia_no` (`membresiaNo`);
