#!/bin/bash

set -euo pipefail

# ============================================================
# CONFIGURACION
# ============================================================

DEV_HOST="10.90.1.197"
PROD_HOST="10.90.1.199"   # Durante la prueba apunta a MAQ

DB_NAME="postgres"
DB_USER="postgres"
DB_PASSWORD="post3008"
SCHEMA_NAME="sn"

BASE_DIR="/home/ingenieria/sn2psql/backup_schema_sn"
DUMP_DIR="${BASE_DIR}/dumps"
LOG_DIR="${BASE_DIR}/logs"
CONTROL_DIR="${BASE_DIR}/control"

FECHA=$(date '+%Y%m%d_%H%M%S')

DUMP_NUEVO="${DUMP_DIR}/sn_dev_${FECHA}.dump"
DUMP_VALIDADO="${DUMP_DIR}/sn_dev_validado.dump"
BACKUP_PROD="${DUMP_DIR}/sn_prod_antes_restore_${FECHA}.dump"

CONTROL_DEV="${CONTROL_DIR}/conteos_dev_${FECHA}.txt"
CONTROL_PROD="${CONTROL_DIR}/conteos_prod_${FECHA}.txt"
DIFERENCIAS="${CONTROL_DIR}/diferencias_${FECHA}.txt"

LOG_FILE="${LOG_DIR}/copia_schema_sn_${FECHA}.log"

# El dump nuevo puede variar hasta un 20% respecto
# del dump validado anterior.
PORCENTAJE_TOLERANCIA=20

# ============================================================
# PREPARACION
# ============================================================

mkdir -p "$DUMP_DIR" "$LOG_DIR" "$CONTROL_DIR"

exec > >(tee -a "$LOG_FILE") 2>&1

export PGPASSWORD="$DB_PASSWORD"

echo "============================================================"
echo "Inicio del proceso: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Origen DEV       : $DEV_HOST"
echo "Destino PROD     : $PROD_HOST"
echo "Base de datos    : $DB_NAME"
echo "Schema           : $SCHEMA_NAME"
echo "Log              : $LOG_FILE"
echo "============================================================"

# ============================================================
# FUNCION PARA CONTAR REGISTROS POR TABLA
# ============================================================

contar_registros()
{
    HOST="$1"
    ARCHIVO_SALIDA="$2"

    psql \
        -X \
        -q \
        -h "$HOST" \
        -U "$DB_USER" \
        -d "$DB_NAME" \
        -v ON_ERROR_STOP=1 \
        -Atc "
            SELECT format(
                'SELECT %L || ''|'' || count(*) FROM %I.%I;',
                tablename,
                schemaname,
                tablename
            )
            FROM pg_tables
            WHERE schemaname = '${SCHEMA_NAME}'
            ORDER BY tablename;
        " |
    psql \
        -X \
        -q \
        -h "$HOST" \
        -U "$DB_USER" \
        -d "$DB_NAME" \
        -v ON_ERROR_STOP=1 \
        -At |
    sort > "$ARCHIVO_SALIDA"
}

# ============================================================
# 1. VALIDAR CONECTIVIDAD
# ============================================================

echo
echo "Validando conexión con DEV..."

psql \
    -X \
    -h "$DEV_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    -v ON_ERROR_STOP=1 \
    -c "SELECT 1;" > /dev/null

echo "Conexión con DEV correcta."

echo "Validando conexión con PROD..."

psql \
    -X \
    -h "$PROD_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    -v ON_ERROR_STOP=1 \
    -c "SELECT 1;" > /dev/null

echo "Conexión con PROD correcta."

# ============================================================
# 2. GENERAR DUMP DE DEV
# ============================================================

echo
echo "Generando dump del schema $SCHEMA_NAME en DEV..."

pg_dump \
    -h "$DEV_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    -n "$SCHEMA_NAME" \
    -Fc \
    -f "$DUMP_NUEVO"

if [ ! -s "$DUMP_NUEVO" ]; then
    echo "ERROR: el dump no existe o tiene tamaño cero."
    exit 1
fi

echo "Dump generado correctamente:"
ls -lh "$DUMP_NUEVO"

# ============================================================
# 3. VALIDAR ESTRUCTURA DEL DUMP
# ============================================================

echo
echo "Validando que el dump pueda ser leído por pg_restore..."

pg_restore --list "$DUMP_NUEVO" > /dev/null

echo "La estructura del dump es válida."

# ============================================================
# 4. COMPARAR TAMAÑO CONTRA EL DUMP VALIDADO ANTERIOR
# ============================================================

echo
echo "Validando tamaño del nuevo dump..."

TAMANIO_NUEVO=$(stat -c%s "$DUMP_NUEVO")

if [ ! -f "$DUMP_VALIDADO" ]; then
    echo "ERROR: no existe un dump validado anterior:"
    echo "$DUMP_VALIDADO"
    echo
    echo "El nuevo dump fue generado, pero el proceso se detiene antes"
    echo "de modificar PROD."
    echo
    echo "Tamaño del nuevo dump: $TAMANIO_NUEVO bytes"
    exit 1
fi

TAMANIO_ANTERIOR=$(stat -c%s "$DUMP_VALIDADO")

TAMANIO_MINIMO=$((TAMANIO_ANTERIOR * (100 - PORCENTAJE_TOLERANCIA) / 100))
TAMANIO_MAXIMO=$((TAMANIO_ANTERIOR * (100 + PORCENTAJE_TOLERANCIA) / 100))

echo "Dump anterior      : $TAMANIO_ANTERIOR bytes"
echo "Dump nuevo         : $TAMANIO_NUEVO bytes"
echo "Tamaño mínimo válido: $TAMANIO_MINIMO bytes"
echo "Tamaño máximo válido: $TAMANIO_MAXIMO bytes"

if [ "$TAMANIO_NUEVO" -lt "$TAMANIO_MINIMO" ]; then
    echo "ERROR: el nuevo dump se encuentra fuera de la tolerancia inferior del 20%."
    echo "No se realizará ninguna modificación en PROD."
    exit 1
fi

if [ "$TAMANIO_NUEVO" -gt "$TAMANIO_MAXIMO" ]; then
    echo "ERROR: el nuevo dump supera en más de un 20% al anterior."
    echo "No se realizará ninguna modificación en PROD."
    exit 1
fi

echo "Validación de tamaño correcta."
echo "El nuevo dump se encuentra dentro de la tolerancia de ±20%."

# ============================================================
# 5. OBTENER CONTEOS DE DEV ANTES DEL RESTORE
# ============================================================

echo
echo "Contando registros por tabla en DEV..."

contar_registros "$DEV_HOST" "$CONTROL_DEV"

echo "Conteos de DEV guardados en:"
echo "$CONTROL_DEV"

cat "$CONTROL_DEV"

# ============================================================
# 6. GENERAR BACKUP PREVIO DE PROD
# ============================================================

echo
echo "Generando backup preventivo del schema $SCHEMA_NAME en PROD..."

pg_dump \
    -h "$PROD_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    -n "$SCHEMA_NAME" \
    -Fc \
    -f "$BACKUP_PROD"

if [ ! -s "$BACKUP_PROD" ]; then
    echo "ERROR: no se pudo generar el backup preventivo de PROD."
    echo "No se realizará el DROP."
    exit 1
fi

pg_restore --list "$BACKUP_PROD" > /dev/null

echo "Backup preventivo de PROD generado y validado:"
ls -lh "$BACKUP_PROD"

# ============================================================
# 7. CONFIRMACION MANUAL ANTES DEL DROP
# ============================================================

echo
echo "============================================================"
echo "ATENCION"
echo "El dump de DEV fue generado y validado."
echo "El backup preventivo de PROD fue generado y validado."
echo
echo "El siguiente paso eliminará el schema $SCHEMA_NAME en PROD:"
echo "$PROD_HOST"
echo "============================================================"
echo

read -r -p "Escriba CONTINUAR para ejecutar el DROP y restore: " CONFIRMACION

if [ "$CONFIRMACION" != "CONTINUAR" ]; then
    echo "Proceso cancelado por el operador."
    exit 1
fi

# ============================================================
# 8. ELIMINAR SCHEMA EN PROD
# ============================================================

echo
echo "Eliminando schema $SCHEMA_NAME en PROD..."

psql \
    -X \
    -h "$PROD_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    -v ON_ERROR_STOP=1 \
    -c "DROP SCHEMA IF EXISTS ${SCHEMA_NAME} CASCADE;"

echo "Schema eliminado."

# ============================================================
# 9. RESTAURAR DUMP EN PROD
# ============================================================

echo
echo "Restaurando dump de DEV en PROD..."

if ! pg_restore \
    --exit-on-error \
    --no-owner \
    -h "$PROD_HOST" \
    -U "$DB_USER" \
    -d "$DB_NAME" \
    "$DUMP_NUEVO"
then
    echo "ERROR: falló la restauración del dump de DEV."
    echo "Se intentará recuperar el backup previo de PROD."

    psql \
        -X \
        -h "$PROD_HOST" \
        -U "$DB_USER" \
        -d "$DB_NAME" \
        -v ON_ERROR_STOP=1 \
        -c "DROP SCHEMA IF EXISTS ${SCHEMA_NAME} CASCADE;"

    pg_restore \
        --exit-on-error \
        --no-owner \
        -h "$PROD_HOST" \
        -U "$DB_USER" \
        -d "$DB_NAME" \
        "$BACKUP_PROD"

    echo "Se restauró el backup anterior de PROD."
    exit 1
fi

echo "Restauración finalizada correctamente."

# ============================================================
# 10. CONTAR REGISTROS EN PROD
# ============================================================

echo
echo "Contando registros por tabla en PROD..."

contar_registros "$PROD_HOST" "$CONTROL_PROD"

echo "Conteos de PROD guardados en:"
echo "$CONTROL_PROD"

cat "$CONTROL_PROD"

# ============================================================
# 11. COMPARAR DEV CONTRA PROD
# ============================================================

echo
echo "Comparando cantidad de registros por tabla..."

if diff -u "$CONTROL_DEV" "$CONTROL_PROD" > "$DIFERENCIAS"; then
    echo "VALIDACION CORRECTA."
    echo "Todas las tablas tienen la misma cantidad de registros."
    rm -f "$DIFERENCIAS"
    VALIDACION_FINAL="CORRECTA"
else
    echo "ERROR DE VALIDACION."
    echo "Existen diferencias entre DEV y PROD:"
    cat "$DIFERENCIAS"
    VALIDACION_FINAL="CON DIFERENCIAS"
fi

TOTAL_TABLAS_DEV=$(wc -l < "$CONTROL_DEV")
TOTAL_TABLAS_PROD=$(wc -l < "$CONTROL_PROD")

TOTAL_FILAS_DEV=$(
    awk -F'|' '{s += $2} END {print s+0}' "$CONTROL_DEV"
)

TOTAL_FILAS_PROD=$(
    awk -F'|' '{s += $2} END {print s+0}' "$CONTROL_PROD"
)

# ============================================================
# 12. RESULTADO FINAL
# ============================================================

echo
echo "============================================================"
echo "RESULTADO FINAL"
echo "============================================================"
echo "Dump utilizado         : $DUMP_NUEVO"
echo "Backup previo de PROD  : $BACKUP_PROD"
echo "Tablas en DEV          : $TOTAL_TABLAS_DEV"
echo "Tablas en PROD         : $TOTAL_TABLAS_PROD"
echo "Total registros DEV    : $TOTAL_FILAS_DEV"
echo "Total registros PROD   : $TOTAL_FILAS_PROD"
echo "Validación final       : $VALIDACION_FINAL"
echo "Log                    : $LOG_FILE"
echo "Finalización           : $(date '+%Y-%m-%d %H:%M:%S')"
echo "============================================================"

if [ "$VALIDACION_FINAL" != "CORRECTA" ]; then
    exit 1
fi

echo
echo "============================================================"
echo "PROMOCION MANUAL DEL DUMP VALIDADO"
echo "============================================================"
echo
echo "La restauración y validaciones finalizaron correctamente."
echo
echo "El dump utilizado en esta ejecución fue:"
echo "$DUMP_NUEVO"
echo
echo "El dump de referencia actual es:"
echo "$DUMP_VALIDADO"
echo
echo "Luego de revisar los logs y validar la operatoria,"
echo "ejecutar el siguiente comando para promover el nuevo"
echo "dump como baseline de referencia:"
echo
echo "cp -p \"$DUMP_NUEVO\" \"$DUMP_VALIDADO\""
echo
echo "IMPORTANTE:"
echo "La promoción es una decisión manual del operador."
echo "Ejecutar únicamente después de revisar los logs,"
echo "los conteos de registros y el resultado general."
echo
echo "============================================================"

