-- =============================================================================
--  inv_solicitud / inv_invitado — esquema de las RÉPLICAS que empuja Tlalpan
-- =============================================================================
--  Base de datos : asturias_api  (servidor PÚBLICO, CL032BACK)
--  Archivo       : database/sql/inv_solicitud_add_replica_tlalpan.sql
--  Fecha         : 2026-08-13
--  Equivale a    : database/migrations/2026_08_13_130000_add_replica_to_inv_solicitud.php
--  Propuesta     : CL001SICAMV2/PROPUESTA_REPLICACION_SOLICITUDES_INVITADOS.md §6.4
--
--  MOTIVO
--  ------
--  Hasta hoy el Portal solo conoce las solicitudes que NACIERON aquí. Tlalpan va a
--  replicar TODAS las vigentes, nazcan donde nazcan, para que el socio pueda crear
--  la reservación sin importar si la capturó él o si se la capturaron en ventanilla.
--
--  Eso exige distinguir de dónde viene cada fila y poder aplicar el mismo snapshot
--  muchas veces sin reescribir ni notificar de más:
--
--    solicitudOrigen            'Tlalpan' = la capturó el club. NO es editable ni
--                               cancelable por el socio: el dueño del dato es Tlalpan
--                               y el siguiente snapshot pisaría cualquier cambio local.
--    solicitudFechaReplica      cuándo se aplicó la última réplica. La escribe el
--                               PORTAL con su propio reloj; no viaja en el payload,
--                               justo para no heredar la deriva entre relojes.
--    solicitudHashReplica       hash del último snapshot aplicado. Es lo que permite
--                               responder "sin cambios" SIN TOCAR NADA cuando Tlalpan
--                               reintenta o reconcilia. Sin él, cada reintento
--                               reescribiría filas y dispararía notificaciones por un
--                               snapshot idéntico.
--    idSolicitudInvitadoTlalpan puntero de origen del invitado replicado.
--
--  POR QUÉ idSolicitudInvitadoTlalpan Y NO idInvitadoTlalpan
--  ---------------------------------------------------------
--  En Tlalpan `inv_invitado` es un CATÁLOGO GLOBAL y `inv_solicitudinvitado` es el
--  pivote POR SOLICITUD. Aquí el invitado ES por solicitud, así que la fila que
--  corresponde uno a uno con la nuestra es la del pivote. Usar `idInvitado` daría
--  colisiones en cuanto el mismo invitado aparezca en dos solicitudes — que es el
--  caso normal, no el raro.
--
--  POR QUÉ NO HAY 'UNIQUE'
--  -----------------------
--  Ni en `idSolicitudTlalpan` (ya existente) ni en `idSolicitudInvitadoTlalpan`. Un
--  payload mal formado debe producir un rechazo controlado y bitacorado, no un 500
--  por violación de índice. Es el mismo criterio con el que se decidió no ponerlo en
--  `idSolicitudTlalpan` (ver inv_solicitud_add_transferencia_portal.sql).
--
--  LO QUE NO SE AGREGA, Y POR QUÉ
--  ------------------------------
--    solicitudNo de Tlalpan       El Portal genera su propio folio (año + 5
--                                 consecutivos, Solicitud::generarNo). Escribir el
--                                 folio de Tlalpan sobre una solicitud de origen
--                                 Portal cambiaría el número que el socio YA VIO y el
--                                 que sale en sus notificaciones. Si más adelante se
--                                 decide mostrar el folio de Tlalpan, es una columna
--                                 nueva, no una sobreescritura de esta.
--    solicitudFechaCalificacion   No se muestra en ninguna pantalla del socio. El
--                                 canal ya la recibe en /estado y la descarta.
--    solicitudMotivoCancelacion   Se usa SOLO para redactar el aviso al socio en el
--                                 momento en que llega; no hay pantalla que lo
--                                 consulte después. Viaja en el payload y se consume
--                                 en tránsito, sin persistirse.
--
--  APLICAR MANUALMENTE
--  -------------------
--    mysql -u <usuario> -p asturias_api < inv_solicitud_add_replica_tlalpan.sql
--
--  RE-EJECUTABLE: cada objeto se crea solo si falta. Correrlo dos veces seguidas no
--  produce error ni cambia datos. Son ALTER de solo-adición sobre tablas InnoDB
--  pequeñas; no reescriben datos y no requieren ventana.
-- =============================================================================

-- -----------------------------------------------------------------------------
--  1. inv_solicitud.solicitudOrigen
-- -----------------------------------------------------------------------------
SET @existe := (
    SELECT COUNT(*) FROM information_schema.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_solicitud'
       AND COLUMN_NAME = 'solicitudOrigen'
);
SET @sql := IF(@existe = 0,
    "ALTER TABLE `inv_solicitud`
       ADD COLUMN `solicitudOrigen` enum('Portal','Tlalpan') NOT NULL DEFAULT 'Portal'
           COMMENT 'Donde nacio la solicitud. Las replicadas desde Tlalpan no son editables por el socio.'
           AFTER `solicitudPuedeReservar`",
    "SELECT 'inv_solicitud.solicitudOrigen ya existe' AS aviso"
);
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;

-- -----------------------------------------------------------------------------
--  2. inv_solicitud.solicitudFechaReplica
-- -----------------------------------------------------------------------------
SET @existe := (
    SELECT COUNT(*) FROM information_schema.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_solicitud'
       AND COLUMN_NAME = 'solicitudFechaReplica'
);
SET @sql := IF(@existe = 0,
    "ALTER TABLE `inv_solicitud`
       ADD COLUMN `solicitudFechaReplica` datetime NULL DEFAULT NULL
           COMMENT 'Ultima replica aplicada desde Tlalpan. La escribe el Portal con su propio reloj.'
           AFTER `solicitudFechaEstado`",
    "SELECT 'inv_solicitud.solicitudFechaReplica ya existe' AS aviso"
);
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;

-- -----------------------------------------------------------------------------
--  3. inv_solicitud.solicitudHashReplica
-- -----------------------------------------------------------------------------
SET @existe := (
    SELECT COUNT(*) FROM information_schema.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_solicitud'
       AND COLUMN_NAME = 'solicitudHashReplica'
);
SET @sql := IF(@existe = 0,
    "ALTER TABLE `inv_solicitud`
       ADD COLUMN `solicitudHashReplica` char(64) NULL DEFAULT NULL
           COMMENT 'Hash del ultimo snapshot aplicado. Permite responder sin reescribir.'
           AFTER `solicitudFechaReplica`",
    "SELECT 'inv_solicitud.solicitudHashReplica ya existe' AS aviso"
);
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;

-- -----------------------------------------------------------------------------
--  4. inv_invitado.idSolicitudInvitadoTlalpan
-- -----------------------------------------------------------------------------
SET @existe := (
    SELECT COUNT(*) FROM information_schema.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_invitado'
       AND COLUMN_NAME = 'idSolicitudInvitadoTlalpan'
);
SET @sql := IF(@existe = 0,
    "ALTER TABLE `inv_invitado`
       ADD COLUMN `idSolicitudInvitadoTlalpan` int NULL DEFAULT NULL
           COMMENT 'PK de inv_solicitudinvitado en Tlalpan. Puntero de origen del invitado replicado. NULL = lo capturo el socio aqui.'
           AFTER `idSolicitud`",
    "SELECT 'inv_invitado.idSolicitudInvitadoTlalpan ya existe' AS aviso"
);
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;

-- -----------------------------------------------------------------------------
--  5. Índice de la reconciliación de invitados
-- -----------------------------------------------------------------------------
--  Compuesto (idSolicitud, idSolicitudInvitadoTlalpan) y no solo la segunda columna:
--  la reconciliación SIEMPRE busca dentro de UNA solicitud —"¿qué fila local
--  corresponde a este invitado del snapshot?"—, nunca por el puntero suelto. Con el
--  índice compuesto esa búsqueda queda cubierta por completo.
-- -----------------------------------------------------------------------------
SET @existe := (
    SELECT COUNT(*) FROM information_schema.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_invitado'
       AND INDEX_NAME = 'idx_invitado_tlalpan'
);
SET @sql := IF(@existe = 0,
    "ALTER TABLE `inv_invitado`
       ADD INDEX `idx_invitado_tlalpan` (`idSolicitud`, `idSolicitudInvitadoTlalpan`)",
    "SELECT 'idx_invitado_tlalpan ya existe' AS aviso"
);
PREPARE st FROM @sql; EXECUTE st; DEALLOCATE PREPARE st;

-- -----------------------------------------------------------------------------
--  VERIFICACIÓN (opcional, tras aplicar)
-- -----------------------------------------------------------------------------
-- SHOW CREATE TABLE `inv_solicitud`\G
-- SHOW CREATE TABLE `inv_invitado`\G
-- SELECT `solicitudOrigen`, COUNT(*) n FROM `inv_solicitud` GROUP BY 1;
--
--  Esperado antes del primer backfill: TODAS en 'Portal'. Ninguna fila existente
--  cambia de significado: el DEFAULT las deja donde ya estaban.

-- -----------------------------------------------------------------------------
--  ROLLBACK
-- -----------------------------------------------------------------------------
-- ALTER TABLE `inv_invitado`
--   DROP INDEX  `idx_invitado_tlalpan`,
--   DROP COLUMN `idSolicitudInvitadoTlalpan`;
-- ALTER TABLE `inv_solicitud`
--   DROP COLUMN `solicitudHashReplica`,
--   DROP COLUMN `solicitudFechaReplica`,
--   DROP COLUMN `solicitudOrigen`;
