-- Diagnostico de esquema para Administracion Portal de Clientes en MAIN.
-- Este archivo es de solo lectura: todas las sentencias ejecutables son SELECT.

SELECT
    '00_INFO' AS seccion,
    DATABASE() AS base_datos,
    NOW() AS ejecutado_en,
    'Administracion Portal de Clientes' AS alcance;

SELECT
    '01_TABLAS' AS seccion,
    esperado.table_name AS tabla,
    esperado.funcion_portal,
    esperado.obligatoria,
    CASE
        WHEN t.table_name IS NULL THEN 'FALTA'
        ELSE 'YA_EXISTE'
    END AS estado,
    t.engine,
    t.table_rows
FROM (
    SELECT 'portal_usuarios' AS table_name, 'usuarios Portal legacy/nuevo, validacion administrativa' AS funcion_portal, 'SI' AS obligatoria UNION ALL
    SELECT 'portal_usuario_documentos', 'documentos personales del usuario Portal', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'requisitos documentales personales por usuario', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'recordatorios documentales del usuario Portal', 'NO' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'expediente documental empresarial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'requisitos documentales empresariales', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'archivos empresariales cargados/revisados', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'historial documental empresarial', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'solicitudes de servicios Portal', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'documentos de solicitudes Portal', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'partidas de solicitudes Portal', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'chat administrativo Portal', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'mensajes y archivos de chat Portal', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'comprobantes de pago de Cobranza', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'aplicaciones multiples de comprobantes Portal', 'SI' UNION ALL
    SELECT 'cotizaciones', 'cotizaciones originadas desde Portal', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'archivos asociados a cotizaciones Portal', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'banners administrables para Portal', 'SI' UNION ALL
    SELECT 'portal_clientes_cat_document_types', 'catalogo de tipos documentales Portal', 'SI' UNION ALL
    SELECT 'legal_documents', 'catalogo de documentos legales Portal', 'SI' UNION ALL
    SELECT 'recibo_muestras', 'flujo operativo desde solicitudes Portal', 'SI' UNION ALL
    SELECT 'cliente_facturas', 'empresa de facturacion vinculada a Portal', 'SI' UNION ALL
    SELECT 'cliente_contacto_facturas', 'contacto/tramitador de facturacion Portal', 'SI' UNION ALL
    SELECT 'cliente_informes', 'empresa de informe visible en administracion Portal', 'SI' UNION ALL
    SELECT 'cliente_factura_x_informes', 'relacion legacy facturacion-informe', 'SI' UNION ALL
    SELECT 'cliente_rep_legal_informes', 'representantes legales de empresa informe', 'NO' UNION ALL
    SELECT 'categorias', 'categoria de menu Portal de Clientes', 'SI' UNION ALL
    SELECT 'modulos', 'modulos administrativos Portal', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'permisos por tipo de usuario', 'SI' UNION ALL
    SELECT 'tipo_usuarios', 'tipos de usuario para permisos administrativos', 'SI' UNION ALL
    SELECT 'password_resets', 'recuperacion de acceso Portal', 'NO'
) AS esperado
LEFT JOIN information_schema.tables AS t
    ON t.table_schema = DATABASE()
    AND t.table_name = esperado.table_name
ORDER BY esperado.obligatoria DESC, esperado.table_name;

SELECT
    '02_COLUMNAS' AS seccion,
    esperado.table_name AS tabla,
    esperado.column_name AS columna,
    esperado.tipo_esperado,
    esperado.funcion_portal,
    esperado.obligatoria,
    CASE
        WHEN c.column_name IS NULL THEN 'FALTA'
        ELSE 'YA_EXISTE'
    END AS estado,
    c.column_type,
    c.is_nullable,
    c.column_default,
    c.extra
FROM (
    SELECT 'portal_usuarios' AS table_name, 'id_portal_usuario' AS column_name, 'INT UNSIGNED PK' AS tipo_esperado, 'identificador usuario Portal' AS funcion_portal, 'SI' AS obligatoria UNION ALL
    SELECT 'portal_usuarios', 'usuario', 'VARCHAR', 'login legacy', 'SI' UNION ALL
    SELECT 'portal_usuarios', 'contrasena', 'VARCHAR', 'password legacy', 'SI' UNION ALL
    SELECT 'portal_usuarios', 'password', 'VARCHAR nullable', 'password esquema nuevo', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'estatus', 'VARCHAR', 'estatus registro Portal', 'SI' UNION ALL
    SELECT 'portal_usuarios', 'active', 'BOOLEAN/INT nullable', 'estatus activo esquema nuevo', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'remember_token', 'VARCHAR nullable', 'recuerdame esquema nuevo', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'sesion_activa', 'BOOLEAN/INT nullable', 'sesion legacy', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_factura', 'INT UNSIGNED nullable', 'empresa facturacion legacy', 'SI' UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_contacto_factura', 'INT UNSIGNED nullable', 'contacto/tramitador facturacion', 'SI' UNION ALL
    SELECT 'portal_usuarios', 'name', 'VARCHAR nullable', 'nombre usuario Portal', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'last_name', 'VARCHAR nullable', 'apellido usuario Portal', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'email', 'VARCHAR nullable', 'correo usuario Portal', 'NO' UNION ALL
    SELECT 'portal_usuarios', 'telefono', 'VARCHAR nullable', 'telefono usuario Portal', 'NO' UNION ALL
    SELECT 'portal_usuario_documentos', 'id', 'INT UNSIGNED PK', 'id documento personal', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'id_portal_usuario', 'INT UNSIGNED', 'usuario propietario', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'id_legal_document', 'INT UNSIGNED', 'documento requerido', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'archivo_nombre', 'VARCHAR nullable', 'nombre original archivo', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'archivo_path', 'VARCHAR', 'ruta archivo personal', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'mime_type', 'VARCHAR nullable', 'tipo MIME', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'size_bytes', 'BIGINT UNSIGNED', 'tamano archivo', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'estatus', 'VARCHAR', 'revision documental', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'comentario_revision', 'TEXT nullable', 'observacion admin', 'SI' UNION ALL
    SELECT 'portal_usuario_documentos', 'fecha_revision', 'DATETIME nullable', 'auditoria revision si existe', 'NO' UNION ALL
    SELECT 'portal_usuario_documentos', 'revisado_at', 'DATETIME nullable', 'auditoria revision alternativa', 'NO' UNION ALL
    SELECT 'portal_usuario_documentos', 'id_usuario_revision', 'INT nullable', 'usuario revisor si existe', 'NO' UNION ALL
    SELECT 'portal_usuario_documentos', 'id_usuario_revisor', 'INT nullable', 'usuario revisor alternativo', 'NO' UNION ALL
    SELECT 'portal_usuario_documentos', 'revisado_por', 'INT nullable', 'usuario revisor legacy', 'NO' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'id', 'INT UNSIGNED PK', 'id requisito personal', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'id_portal_usuario', 'INT UNSIGNED', 'usuario requerido', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'id_legal_document', 'INT UNSIGNED', 'documento requerido', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'client_type_id', 'INT UNSIGNED nullable', 'tipo documental Portal', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'tipo_documento', 'VARCHAR nullable', 'snapshot tipo documento', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'origen', 'VARCHAR', 'origen personal/empresa', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'aplica_por_registro', 'VARCHAR', 'motivo requisito', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'estatus', 'VARCHAR', 'estado requisito', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'requerido', 'TINYINT', 'obligatoriedad', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'fecha_snapshot', 'TIMESTAMP', 'fecha snapshot', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'captured_at', 'TIMESTAMP', 'captura requisito', 'SI' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'id_portal_usuario', 'INT UNSIGNED', 'usuario recordatorio', 'NO' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'id_legal_document', 'INT UNSIGNED', 'documento recordatorio', 'NO' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'dismissed_until', 'TIMESTAMP nullable', 'posponer recordatorio', 'NO' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'last_dismissed_at', 'TIMESTAMP nullable', 'ultima omision recordatorio', 'NO' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'id_portal_empresa_documento_expediente', 'INT UNSIGNED PK', 'id expediente empresarial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'empresa_tipo', 'VARCHAR', 'facturacion/informe', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'empresa_id', 'INT UNSIGNED', 'id empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'client_type_id', 'INT UNSIGNED nullable', 'tipo documental empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'id_portal_usuario_creo', 'INT UNSIGNED nullable', 'usuario creador expediente', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_expedientes', 'snapshot_creado_en', 'TIMESTAMP nullable', 'fecha snapshot expediente', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'id_portal_empresa_documento_requisito', 'INT UNSIGNED PK', 'id requisito empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'id_portal_empresa_documento_expediente', 'INT UNSIGNED', 'expediente empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'id_legal_document', 'INT UNSIGNED', 'documento requerido empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'client_type_id', 'INT UNSIGNED nullable', 'tipo documental empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'tipo_documento', 'VARCHAR nullable', 'snapshot tipo empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'requerido', 'TINYINT', 'obligatoriedad empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'estatus', 'VARCHAR', 'estado requisito empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_requisitos', 'fecha_snapshot', 'TIMESTAMP', 'fecha snapshot requisito', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'id_portal_empresa_documento', 'INT UNSIGNED PK', 'id documento empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'id_portal_empresa_documento_expediente', 'INT UNSIGNED', 'expediente propietario', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'id_legal_document', 'INT UNSIGNED', 'documento legal empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'archivo_nombre', 'VARCHAR nullable', 'nombre archivo empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'archivo_path', 'VARCHAR', 'ruta archivo empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'mime_type', 'VARCHAR nullable', 'tipo MIME empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'size_bytes', 'BIGINT UNSIGNED nullable', 'tamano empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'estatus', 'VARCHAR', 'revision empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'comentario_revision', 'TEXT nullable', 'observacion empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'id_portal_usuario_subio', 'INT UNSIGNED nullable', 'usuario que subio', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'id_usuario_reviso', 'INT UNSIGNED nullable', 'admin revisor', 'SI' UNION ALL
    SELECT 'portal_empresa_documentos', 'revisado_en', 'DATETIME nullable', 'fecha revision empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'id_portal_empresa_documento_historial', 'INT UNSIGNED PK', 'id historial empresa', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'id_portal_empresa_documento_expediente', 'INT UNSIGNED', 'expediente historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'id_legal_document', 'INT UNSIGNED', 'documento historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'accion', 'VARCHAR', 'accion historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'archivo_nombre', 'VARCHAR nullable', 'archivo historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'archivo_path', 'VARCHAR nullable', 'ruta historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'mime_type', 'VARCHAR nullable', 'MIME historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'size_bytes', 'BIGINT UNSIGNED nullable', 'tamano historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'estatus', 'VARCHAR nullable', 'estatus historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'comentario_revision', 'TEXT nullable', 'comentario historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'id_portal_usuario', 'INT UNSIGNED nullable', 'usuario Portal historial', 'SI' UNION ALL
    SELECT 'portal_empresa_documento_historiales', 'id_usuario', 'INT UNSIGNED nullable', 'admin historial', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_portal_solicitud_prueba', 'INT UNSIGNED PK', 'id solicitud Portal', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'folio', 'VARCHAR nullable', 'folio solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'numero_informe', 'VARCHAR nullable', 'folio informe sincronizado', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'tipo_solicitud', 'VARCHAR nullable', 'laboratorio/arm', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'estatus', 'VARCHAR', 'estatus solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'fecha_entrega_documentacion', 'DATETIME nullable', 'entrega documental', 'NO' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'fecha_muestra_recibida', 'DATETIME nullable', 'muestra fisica recibida', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_portal_usuario', 'INT UNSIGNED', 'usuario solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_cliente_factura', 'INT UNSIGNED nullable', 'empresa facturacion solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_cliente_informe', 'INT UNSIGNED nullable', 'empresa informe solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_cliente_contacto_factura', 'INT UNSIGNED nullable', 'contacto solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_recibo_muestra', 'INT UNSIGNED nullable', 'flujo recibo creado', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_muestra', 'INT UNSIGNED nullable', 'muestra creada', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_inspeccion_muestra', 'INT UNSIGNED nullable', 'inspeccion creada', 'SI' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_programacion_muestra', 'INT UNSIGNED nullable', 'programacion sincronizada', 'NO' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_international_portal_report', 'INT UNSIGNED nullable', 'flujo ARM legacy', 'NO' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'ingreso_desde', 'VARCHAR nullable', 'origen solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'id_portal_solicitud_documento', 'INT UNSIGNED PK', 'id documento solicitud', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'id_portal_solicitud_prueba', 'INT UNSIGNED', 'solicitud propietaria', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'id_legal_document', 'INT UNSIGNED nullable', 'catalogo documento', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'archivo', 'VARCHAR/TEXT nullable', 'archivo original', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'nombre_archivo_original', 'VARCHAR nullable', 'nombre original', 'NO' UNION ALL
    SELECT 'portal_solicitud_documentos', 'origen_archivo', 'VARCHAR nullable', 'origen Portal/LAB', 'NO' UNION ALL
    SELECT 'portal_solicitud_documentos', 'estado', 'VARCHAR', 'estado revision documento', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'comentario', 'TEXT nullable', 'observacion revision', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'archivo_correccion', 'VARCHAR/TEXT nullable', 'archivo correccion admin', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'nombre_archivo_correccion_original', 'VARCHAR nullable', 'nombre correccion admin', 'NO' UNION ALL
    SELECT 'portal_solicitud_documentos', 'origen_archivo_correccion', 'VARCHAR nullable', 'origen correccion', 'NO' UNION ALL
    SELECT 'portal_solicitud_documentos', 'fecha_revision', 'DATETIME nullable', 'fecha revision documento', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'document_snapshot', 'VARCHAR nullable', 'snapshot documento', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'description_snapshot', 'TEXT nullable', 'snapshot descripcion', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'tipo_documento_snapshot', 'VARCHAR nullable', 'snapshot tipo', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'extensiones_snapshot', 'VARCHAR nullable', 'snapshot extensiones', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'requerido_snapshot', 'TINYINT nullable', 'snapshot requerido', 'SI' UNION ALL
    SELECT 'portal_solicitud_documentos', 'template_path_snapshot', 'VARCHAR nullable', 'snapshot template', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_portal_solicitud_prueba_partida', 'INT UNSIGNED PK', 'id partida Portal', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_portal_solicitud_prueba', 'INT UNSIGNED', 'solicitud de partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'partida', 'INT/VARCHAR', 'numero partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'tipo_solicitud', 'VARCHAR nullable', 'laboratorio/arm por partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_servicio', 'INT UNSIGNED nullable', 'servicio solicitado', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_norma', 'INT UNSIGNED nullable', 'norma', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_estandar_internacional', 'INT UNSIGNED nullable', 'estandar internacional', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_norma_estandar_correlacion', 'INT UNSIGNED nullable', 'correlacion norma/estandar', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'observaciones', 'TEXT nullable', 'observaciones partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'estatus_revision', 'VARCHAR', 'revision administrativa partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'fecha_recibida', 'DATETIME nullable', 'muestra recibida partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'fecha_revision', 'DATETIME nullable', 'fecha revision partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'comentario_revision', 'TEXT nullable', 'comentario revision partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_usuario_revision', 'INT UNSIGNED nullable', 'admin revisor partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_recibo_muestra', 'INT UNSIGNED nullable', 'recibo generado por partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_muestra', 'INT UNSIGNED nullable', 'muestra generada por partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_inspeccion_muestra', 'INT UNSIGNED nullable', 'inspeccion generada por partida', 'SI' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_international_portal_report', 'INT UNSIGNED nullable', 'reporte ARM', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'archivo_informe_internacional', 'VARCHAR/TEXT nullable', 'archivo informe internacional', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'archivo_informe_internacional_nombre', 'VARCHAR nullable', 'nombre informe internacional', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'archivo_informe_internacional_extension', 'VARCHAR nullable', 'extension informe internacional', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'archivo_informe_internacional_tamano', 'BIGINT nullable', 'tamano informe internacional', 'NO' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'archivo_informe_internacional_mime', 'VARCHAR nullable', 'MIME informe internacional', 'NO' UNION ALL
    SELECT 'portal_chat_conversaciones', 'id_portal_chat_conversacion', 'INT UNSIGNED PK', 'id conversacion chat', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'id_usuario_cliente', 'INT UNSIGNED', 'usuario Portal cliente', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'id_usuario_administrador', 'INT UNSIGNED nullable', 'admin asignado', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'asunto', 'VARCHAR nullable', 'asunto conversacion', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'estatus', 'VARCHAR', 'estado conversacion', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'estatus_asignacion', 'VARCHAR', 'sin_asignar/asignado', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'tomado_at', 'DATETIME nullable', 'fecha asignacion', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'finalizado_at', 'DATETIME nullable', 'fecha cierre', 'SI' UNION ALL
    SELECT 'portal_chat_conversaciones', 'ultimo_mensaje_at', 'DATETIME nullable', 'ordenamiento por actividad', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'id_portal_chat_mensaje', 'INT UNSIGNED PK', 'id mensaje chat', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'id_portal_chat_conversacion', 'INT UNSIGNED', 'conversacion propietaria', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'id_usuario', 'INT UNSIGNED nullable', 'usuario emisor admin/cliente', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'tipo_usuario', 'VARCHAR', 'usuario_admin/cliente', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'mensaje', 'TEXT nullable', 'texto mensaje', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'archivo', 'VARCHAR/TEXT nullable', 'ruta archivo chat', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'archivo_original', 'VARCHAR nullable', 'nombre original archivo', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'mime_type', 'VARCHAR nullable', 'MIME archivo chat', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'extension', 'VARCHAR nullable', 'extension archivo chat', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'peso', 'BIGINT nullable', 'peso archivo chat', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'origen', 'VARCHAR', 'portal_clientes/seatsa_lab', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'leido', 'TINYINT', 'estado lectura', 'SI' UNION ALL
    SELECT 'portal_chat_mensajes', 'fecha_leido', 'DATETIME nullable', 'fecha lectura', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'id_pago_comprobante', 'INT UNSIGNED PK', 'id comprobante', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'id_cliente_contacto_factura', 'INT UNSIGNED nullable', 'contacto que subio comprobante', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'estatus_revision', 'VARCHAR nullable', 'revision comprobante', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'origen_carga', 'VARCHAR nullable', 'aislar origen Portal', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'cargado_por_detalle', 'TEXT nullable', 'detalle de carga Portal', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'id_usuario_portal_subio', 'INT UNSIGNED nullable', 'usuario Portal que subio', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'id_usuario_subio', 'INT UNSIGNED nullable', 'usuario LAB que subio', 'NO' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_pago_comprobante_aplicacion', 'BIGINT UNSIGNED PK', 'id aplicacion', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_pago_comprobante', 'INT UNSIGNED', 'comprobante origen', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_cliente_factura', 'INT UNSIGNED nullable', 'empresa facturacion aplicada', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_factura', 'INT UNSIGNED nullable', 'factura aplicada', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_servicio_cliente_reporte', 'INT UNSIGNED nullable', 'informe/servicio aplicado', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'factura', 'VARCHAR nullable', 'folio factura snapshot', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'numero_informe', 'VARCHAR nullable', 'numero informe snapshot', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'referencia', 'VARCHAR nullable', 'referencia aplicacion', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'monto', 'DECIMAL(14,2)', 'monto aplicado', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'monto_requerido', 'DECIMAL nullable', 'monto requerido usado por codigo', 'SI' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'estatus', 'VARCHAR', 'estatus aplicacion', 'SI' UNION ALL
    SELECT 'cotizaciones', 'id_cotizacion', 'INT UNSIGNED PK', 'id cotizacion', 'SI' UNION ALL
    SELECT 'cotizaciones', 'id_cliente_factura', 'INT UNSIGNED nullable', 'empresa facturacion cotizacion', 'SI' UNION ALL
    SELECT 'cotizaciones', 'id_cliente_contacto_factura', 'INT UNSIGNED nullable', 'contacto cotizacion Portal', 'SI' UNION ALL
    SELECT 'cotizaciones', 'origen_carga', 'VARCHAR nullable', 'origen portal_clientes', 'SI' UNION ALL
    SELECT 'cotizaciones', 'estatus_portal', 'VARCHAR nullable', 'estado administrativo Portal', 'SI' UNION ALL
    SELECT 'cotizaciones', 'id_portal_usuario', 'INT UNSIGNED nullable', 'usuario Portal solicitante', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'id_cotizacion_archivo_portal', 'INT UNSIGNED PK', 'id archivo cotizacion', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'id_cotizacion', 'INT UNSIGNED', 'cotizacion propietaria', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'nombre_archivo', 'VARCHAR', 'nombre archivo enviado', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'ruta_archivo', 'VARCHAR(500)', 'ruta archivo enviado', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'clave_archivo', 'VARCHAR', 'clave unica por cotizacion', 'SI' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'tipo', 'VARCHAR nullable', 'tipo archivo', 'NO' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'origen', 'VARCHAR nullable', 'origen archivo', 'NO' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'mime_type', 'VARCHAR nullable', 'MIME archivo', 'NO' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'size_bytes', 'BIGINT UNSIGNED nullable', 'tamano archivo', 'NO' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'enviado_en', 'TIMESTAMP nullable', 'fecha envio', 'NO' UNION ALL
    SELECT 'recibo_muestras', 'id_recibo_muestra', 'INT UNSIGNED PK', 'id recibo muestra', 'SI' UNION ALL
    SELECT 'recibo_muestras', 'id_portal_solicitud_prueba', 'INT UNSIGNED nullable', 'solicitud Portal origen', 'SI' UNION ALL
    SELECT 'recibo_muestras', 'id_cliente_contacto_factura', 'INT UNSIGNED nullable', 'contacto del recibo', 'SI' UNION ALL
    SELECT 'recibo_muestras', 'origen_ingreso', 'VARCHAR default seatsa', 'origen laboratorio/arm/seatsa', 'SI' UNION ALL
    SELECT 'legal_documents', 'id', 'INT UNSIGNED PK', 'id documento legal', 'SI' UNION ALL
    SELECT 'legal_documents', 'document', 'VARCHAR', 'nombre documento', 'SI' UNION ALL
    SELECT 'legal_documents', 'description', 'TEXT/VARCHAR nullable', 'descripcion documento', 'SI' UNION ALL
    SELECT 'legal_documents', 'information', 'TEXT/VARCHAR nullable', 'informacion legacy', 'NO' UNION ALL
    SELECT 'legal_documents', 'client_type_id', 'INT UNSIGNED nullable', 'tipo documental Portal', 'SI' UNION ALL
    SELECT 'legal_documents', 'tipo_documento', 'VARCHAR nullable', 'texto tipo documental', 'SI' UNION ALL
    SELECT 'legal_documents', 'extensiones', 'VARCHAR nullable', 'extensiones permitidas', 'SI' UNION ALL
    SELECT 'legal_documents', 'requerido', 'TINYINT nullable', 'obligatorio Portal', 'SI' UNION ALL
    SELECT 'legal_documents', 'sin_template', 'TINYINT nullable', 'documento sin plantilla', 'SI' UNION ALL
    SELECT 'legal_documents', 'lleva_template', 'TINYINT nullable', 'documento con plantilla', 'NO' UNION ALL
    SELECT 'legal_documents', 'template_disk', 'VARCHAR nullable', 'disco plantilla', 'SI' UNION ALL
    SELECT 'legal_documents', 'template_path', 'VARCHAR nullable', 'ruta plantilla', 'SI' UNION ALL
    SELECT 'legal_documents', 'active', 'TINYINT nullable', 'activo catalogo', 'SI' UNION ALL
    SELECT 'portal_clientes_cat_document_types', 'id', 'INT UNSIGNED PK', 'id tipo documento Portal', 'SI' UNION ALL
    SELECT 'portal_clientes_cat_document_types', 'name', 'VARCHAR', 'nombre tipo documento Portal', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'id', 'INT UNSIGNED PK', 'id banner Portal', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'start_date', 'DATE', 'inicio vigencia banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'end_date', 'DATE', 'fin vigencia banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'banner_url', 'VARCHAR/TEXT', 'ruta imagen banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'description', 'VARCHAR(255) nullable', 'descripcion banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'external_url', 'VARCHAR nullable', 'liga externa banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'active', 'TINYINT', 'activo banner', 'SI' UNION ALL
    SELECT 'portal_clientes_banners', 'order', 'INT', 'orden destacado 1-5', 'SI' UNION ALL
    SELECT 'cliente_facturas', 'prospecto', 'TINYINT/INT', 'marcado cliente no prospecto para Portal', 'SI' UNION ALL
    SELECT 'cliente_facturas', 'active', 'TINYINT/INT nullable', 'activacion empresa facturacion', 'NO' UNION ALL
    SELECT 'cliente_informes', 'rfc', 'VARCHAR(13) nullable', 'busqueda/visualizacion RFC empresa informe', 'NO' UNION ALL
    SELECT 'cliente_rep_legal_informes', 'id_cliente_informe', 'INT UNSIGNED', 'representantes por empresa informe', 'NO' UNION ALL
    SELECT 'modulos', 'name_space', 'VARCHAR', 'identificador modulo admin', 'SI' UNION ALL
    SELECT 'modulos', 'id_categoria', 'INT UNSIGNED', 'categoria menu', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'id_modulo', 'INT UNSIGNED', 'permiso modulo', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'id_tipo_usuario', 'INT UNSIGNED', 'tipo usuario permiso', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'altas', 'TINYINT', 'permiso acceso/admin', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'crear', 'TINYINT', 'permiso crear', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'actualizar', 'TINYINT', 'permiso actualizar', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'eliminar', 'TINYINT', 'permiso eliminar', 'SI' UNION ALL
    SELECT 'usuarios_x_modulos', 'verqr', 'TINYINT', 'permiso ver', 'SI'
) AS esperado
LEFT JOIN information_schema.columns AS c
    ON c.table_schema = DATABASE()
    AND c.table_name = esperado.table_name
    AND c.column_name = esperado.column_name
ORDER BY esperado.table_name, esperado.obligatoria DESC, esperado.column_name;

SELECT
    '03_INDICES' AS seccion,
    esperado.table_name AS tabla,
    esperado.index_name AS indice,
    esperado.columnas,
    esperado.tipo,
    esperado.motivo,
    CASE
        WHEN s.index_name IS NULL THEN 'FALTA'
        ELSE 'YA_EXISTE'
    END AS estado,
    GROUP_CONCAT(s.column_name ORDER BY s.seq_in_index SEPARATOR ',') AS columnas_detectadas,
    MIN(s.non_unique) AS non_unique
FROM (
    SELECT 'portal_usuario_documentos' AS table_name, 'portal_usuario_documentos_unique' AS index_name, 'id_portal_usuario,id_legal_document' AS columnas, 'UNIQUE' AS tipo, 'evita duplicar documento personal por usuario' AS motivo UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'portal_doc_req_usuario_documento_unique', 'id_portal_usuario,id_legal_document', 'UNIQUE', 'evita duplicar requisito personal' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'portal_doc_rem_usuario_documento_unique', 'id_portal_usuario,id_legal_document', 'UNIQUE', 'evita duplicar recordatorio' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'idx_id_pago_comprobante', 'id_pago_comprobante', 'INDEX', 'consulta aplicaciones por comprobante' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'idx_id_cliente_factura', 'id_cliente_factura', 'INDEX', 'consulta aplicaciones por empresa facturacion' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'idx_id_factura', 'id_factura', 'INDEX', 'consulta aplicaciones por factura' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'idx_id_servicio_cliente_reporte', 'id_servicio_cliente_reporte', 'INDEX', 'consulta aplicaciones por informe' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'idx_numero_informe', 'numero_informe', 'INDEX', 'busqueda por numero informe' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'cotizacion_archivos_portal_unique', 'id_cotizacion,clave_archivo', 'UNIQUE', 'evita duplicar archivo por cotizacion y clave' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'idx_id_cotizacion', 'id_cotizacion', 'INDEX', 'consulta archivos por cotizacion'
) AS esperado
LEFT JOIN information_schema.statistics AS s
    ON s.table_schema = DATABASE()
    AND s.table_name = esperado.table_name
    AND s.index_name = esperado.index_name
GROUP BY
    esperado.table_name,
    esperado.index_name,
    esperado.columnas,
    esperado.tipo,
    esperado.motivo
ORDER BY esperado.table_name, esperado.index_name;

SELECT
    '04_FKS' AS seccion,
    esperado.table_name AS tabla,
    esperado.column_name AS columna,
    esperado.referenced_table_name AS tabla_referenciada,
    esperado.referenced_column_name AS columna_referenciada,
    CASE
        WHEN k.constraint_name IS NULL THEN 'FALTA'
        ELSE 'YA_EXISTE'
    END AS estado,
    k.constraint_name,
    k.update_rule,
    k.delete_rule
FROM (
    SELECT 'portal_usuario_documentos' AS table_name, 'id_portal_usuario' AS column_name, 'portal_usuarios' AS referenced_table_name, 'id_portal_usuario' AS referenced_column_name UNION ALL
    SELECT 'portal_usuario_documentos', 'id_legal_document', 'legal_documents', 'id' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'id_portal_usuario', 'portal_usuarios', 'id_portal_usuario' UNION ALL
    SELECT 'portal_usuario_documento_requisitos', 'id_legal_document', 'legal_documents', 'id' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'id_portal_usuario', 'portal_usuarios', 'id_portal_usuario' UNION ALL
    SELECT 'portal_usuario_documento_recordatorios', 'id_legal_document', 'legal_documents', 'id' UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_contacto_factura', 'cliente_contacto_facturas', 'id_cliente_contacto_factura' UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_factura', 'cliente_facturas', 'id_cliente_factura' UNION ALL
    SELECT 'recibo_muestras', 'id_portal_solicitud_prueba', 'portal_solicitud_pruebas', 'id_portal_solicitud_prueba'
) AS esperado
LEFT JOIN (
    SELECT
        kcu.table_name,
        kcu.column_name,
        kcu.referenced_table_name,
        kcu.referenced_column_name,
        kcu.constraint_name,
        rc.update_rule,
        rc.delete_rule
    FROM information_schema.key_column_usage AS kcu
    LEFT JOIN information_schema.referential_constraints AS rc
        ON rc.constraint_schema = kcu.constraint_schema
        AND rc.constraint_name = kcu.constraint_name
    WHERE kcu.table_schema = DATABASE()
        AND kcu.referenced_table_name IS NOT NULL
) AS k
    ON k.table_name = esperado.table_name
    AND k.column_name = esperado.column_name
    AND k.referenced_table_name = esperado.referenced_table_name
    AND k.referenced_column_name = esperado.referenced_column_name
ORDER BY esperado.table_name, esperado.column_name;

SELECT
    '05_TIPOS_IDS_CRITICOS' AS seccion,
    c.table_name AS tabla,
    c.column_name AS columna,
    c.column_type,
    c.data_type,
    c.is_nullable,
    c.column_key,
    c.extra
FROM information_schema.columns AS c
JOIN (
    SELECT 'portal_usuarios' AS table_name, 'id_portal_usuario' AS column_name UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_factura' UNION ALL
    SELECT 'portal_usuarios', 'id_cliente_contacto_factura' UNION ALL
    SELECT 'cliente_facturas', 'id_cliente_factura' UNION ALL
    SELECT 'cliente_contacto_facturas', 'id_cliente_contacto_factura' UNION ALL
    SELECT 'cliente_informes', 'id_cliente_informe' UNION ALL
    SELECT 'legal_documents', 'id' UNION ALL
    SELECT 'portal_solicitud_pruebas', 'id_portal_solicitud_prueba' UNION ALL
    SELECT 'portal_solicitud_prueba_partidas', 'id_portal_solicitud_prueba_partida' UNION ALL
    SELECT 'recibo_muestras', 'id_recibo_muestra' UNION ALL
    SELECT 'muestras', 'id_muestra' UNION ALL
    SELECT 'inspeccion_muestras', 'id_inspeccion_muestra' UNION ALL
    SELECT 'programacion_muestras', 'id_programacion_muestra' UNION ALL
    SELECT 'cobranza_pago_comprobantes', 'id_pago_comprobante' UNION ALL
    SELECT 'cobranza_pago_comprobante_aplicaciones', 'id_pago_comprobante' UNION ALL
    SELECT 'cotizaciones', 'id_cotizacion' UNION ALL
    SELECT 'cotizacion_archivos_portal', 'id_cotizacion' UNION ALL
    SELECT 'facturas', 'id_factura' UNION ALL
    SELECT 'servicio_cliente_reportes', 'id_servicio_cliente_reporte'
) AS esperado
    ON esperado.table_name = c.table_name
    AND esperado.column_name = c.column_name
WHERE c.table_schema = DATABASE()
ORDER BY c.table_name, c.column_name;

SELECT
    '06_CATEGORIA_PORTAL' AS seccion,
    esperado.nombre AS nombre_esperado,
    COUNT(c.id_categoria) AS registros_detectados,
    GROUP_CONCAT(c.id_categoria ORDER BY c.id_categoria SEPARATOR ',') AS ids_detectados
FROM (SELECT 'Portal de Clientes' AS nombre) AS esperado
LEFT JOIN categorias AS c
    ON c.nombre = esperado.nombre
GROUP BY esperado.nombre;

SELECT
    '07_MODULOS_PORTAL' AS seccion,
    esperado.name_space,
    esperado.nombre_esperado,
    CASE
        WHEN m.id_modulo IS NULL THEN 'FALTA'
        ELSE 'YA_EXISTE'
    END AS estado,
    m.id_modulo,
    m.nombre AS nombre_actual,
    m.activo,
    m.orden,
    m.id_categoria,
    c.nombre AS categoria_actual
FROM (
    SELECT 'portal_clientes_admin' AS name_space, 'Portal de clientes administrador' AS nombre_esperado UNION ALL
    SELECT 'portal_clientes_solicitudes_servicios', 'Solicitudes de servicios portal clientes'
) AS esperado
LEFT JOIN modulos AS m
    ON m.name_space = esperado.name_space
LEFT JOIN categorias AS c
    ON c.id_categoria = m.id_categoria
ORDER BY esperado.name_space, m.id_modulo;

SELECT
    '08_DUPLICADOS_MODULOS_PORTAL' AS seccion,
    m.name_space,
    COUNT(*) AS total_registros,
    GROUP_CONCAT(m.id_modulo ORDER BY m.id_modulo SEPARATOR ',') AS ids_modulo
FROM modulos AS m
WHERE m.name_space IN ('portal_clientes_admin', 'portal_clientes_solicitudes_servicios')
GROUP BY m.name_space
HAVING COUNT(*) > 1;

SELECT
    '09_PERMISOS_PORTAL' AS seccion,
    m.name_space,
    m.id_modulo,
    ux.id_tipo_usuario,
    ux.altas,
    ux.crear,
    ux.actualizar,
    ux.eliminar,
    ux.verqr,
    ux.gerente
FROM modulos AS m
LEFT JOIN usuarios_x_modulos AS ux
    ON ux.id_modulo = m.id_modulo
WHERE m.name_space IN ('portal_clientes_admin', 'portal_clientes_solicitudes_servicios')
ORDER BY m.name_space, ux.id_tipo_usuario;

SELECT
    '10_TIPOS_USUARIO_DISPONIBLES' AS seccion,
    c.column_name,
    c.column_type,
    c.column_key
FROM information_schema.columns AS c
WHERE c.table_schema = DATABASE()
    AND c.table_name = 'tipo_usuarios'
ORDER BY c.ordinal_position;

SELECT
    '11_CONSULTAS_CONTEO_DATOS' AS seccion,
    'mark_portal_cliente_facturas_as_clients' AS migracion,
    'cliente_facturas enlazadas a portal_usuarios con prospecto=1' AS condicion,
    'SELECT COUNT(*) AS registros_potenciales FROM cliente_facturas cf INNER JOIN portal_usuarios pu ON pu.id_cliente_factura = cf.id_cliente_factura WHERE pu.id_cliente_factura IS NOT NULL AND cf.prospecto = 1;' AS consulta_select
UNION ALL
SELECT
    '11_CONSULTAS_CONTEO_DATOS',
    'mark_portal_cliente_facturas_as_clients_con_deleted_at',
    'misma condicion excluyendo cliente_facturas.deleted_at si la columna existe',
    'SELECT COUNT(*) AS registros_potenciales FROM cliente_facturas cf INNER JOIN portal_usuarios pu ON pu.id_cliente_factura = cf.id_cliente_factura WHERE pu.id_cliente_factura IS NOT NULL AND cf.prospecto = 1 AND cf.deleted_at IS NULL;'
UNION ALL
SELECT
    '11_CONSULTAS_CONTEO_DATOS',
    'add_origen_ingreso_to_recibo_muestras',
    'recibo_muestras ligados a portal_solicitud_pruebas por id_portal_solicitud_prueba',
    'SELECT COUNT(*) AS recibos_portal FROM recibo_muestras rm INNER JOIN portal_solicitud_pruebas p ON p.id_portal_solicitud_prueba = rm.id_portal_solicitud_prueba WHERE rm.id_portal_solicitud_prueba IS NOT NULL;'
UNION ALL
SELECT
    '11_CONSULTAS_CONTEO_DATOS',
    'add_origen_ingreso_to_recibo_muestras_arm',
    'recibos Portal que se clasifican como ARM por tipo_solicitud o reporte internacional',
    'SELECT COUNT(*) AS recibos_arm FROM recibo_muestras rm INNER JOIN portal_solicitud_pruebas p ON p.id_portal_solicitud_prueba = rm.id_portal_solicitud_prueba WHERE rm.id_portal_solicitud_prueba IS NOT NULL AND (LOWER(TRIM(COALESCE(p.tipo_solicitud, ''''))) = ''arm'' OR p.id_estandar_internacional IS NOT NULL OR p.id_international_portal_report IS NOT NULL);'
UNION ALL
SELECT
    '11_CONSULTAS_CONTEO_DATOS',
    'normalize_portal_clientes_banner_urls',
    'banners con URL absoluta o prefijo storage que se normalizaria',
    'SELECT COUNT(*) AS banners_a_normalizar FROM portal_clientes_banners WHERE banner_url IS NOT NULL AND TRIM(banner_url) <> '''' AND (banner_url LIKE ''%/storage/%'' OR banner_url LIKE ''storage/%'');';

SELECT
    '12_VALORES_ORIGEN_PORTAL' AS seccion,
    esperado.table_name AS tabla,
    esperado.column_name AS columna,
    esperado.valor_esperado,
    CASE
        WHEN c.column_name IS NULL THEN 'COLUMNA_FALTA'
        ELSE 'COLUMNA_EXISTE'
    END AS estado_columna
FROM (
    SELECT 'cobranza_pago_comprobantes' AS table_name, 'origen_carga' AS column_name, 'portal_clientes' AS valor_esperado UNION ALL
    SELECT 'cotizaciones', 'origen_carga', 'portal_clientes' UNION ALL
    SELECT 'portal_chat_mensajes', 'origen', 'portal_clientes/seatsa_lab' UNION ALL
    SELECT 'portal_solicitud_documentos', 'origen_archivo', 'portal_clientes/seatsa_lab' UNION ALL
    SELECT 'recibo_muestras', 'origen_ingreso', 'seatsa/laboratorio/arm'
) AS esperado
LEFT JOIN information_schema.columns AS c
    ON c.table_schema = DATABASE()
    AND c.table_name = esperado.table_name
    AND c.column_name = esperado.column_name
ORDER BY esperado.table_name, esperado.column_name;
