#!/bin/bash

# Configuración inicial
readonly LOG_DIR="/var/logs/deploy_logs"
readonly TEMP_DIR="/tmp/deploy_temp/npw"
readonly BASE_URL="http://maestro.datapar.com/artifactory/datapar/NPW/APP"

# Archivos y aplicaciones
readonly ARCHIVO_WAR="scpp.war"
readonly ARCHIVO_FRONTEND="ProduccionWeb.zip"
readonly ARCHIVO_REPORTS="reports.war"
readonly APP_NAME="scpp"
readonly APP_NAME_FRONTEND="ProduccionWeb"
readonly APP_NAME_REPORTS="reports"
readonly ARCHIVO_PROP="scpp.properties"
readonly ARCHIVO_PROP_REP="reports.properties"

# Configurar logging
setup_logging() {
    mkdir -p "$LOG_DIR"
    find "$LOG_DIR" -type f -name "deploy_npw_*.log" -delete
    readonly LOG_FILE="$LOG_DIR/deploy_npw_$(date +'%Y-%m-%d').log"
}

# Función de logging optimizada
log() {
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $1 $2" | tee -a "$LOG_FILE"
}

# Función para limpiar archivos generados en caso de error
cleanup_on_error() {
    log INFO "Limpiando archivos generados debido a error..."
    
    # Limpiar directorio temporal completo
    if [[ -d "$TEMP_DIR" ]]; then
        rm -rf "$TEMP_DIR" 2>/dev/null || log WARNING "No se pudo limpiar $TEMP_DIR"
    fi
    
    # Limpiar archivos locales si existen
    cleanup_file "$ARCHIVO_FRONTEND"
    cleanup_file "$ARCHIVO_WAR"
    cleanup_file "$ARCHIVO_REPORTS"
    
    # Limpiar directorios de aplicaciones si existen
    cleanup_directory "$APP_NAME_FRONTEND"
    
    log INFO "Limpieza completada"
}

# Trap para manejar errores y señales
trap 'cleanup_on_error; exit 1' ERR EXIT

# Función para verificar directorios
verify_directory() {
    local dir="$1"
    local description="$2"
    
    if [[ ! -d "$dir" ]]; then
        log ERROR "No se encontró $description: $dir"
        return 1
    fi
    return 0
}

# Función para limpiar directorio
cleanup_directory() {
    local dir="$1"
    [[ -d "$dir" ]] && rm -rf "$dir"
}

# Función para limpiar archivo
cleanup_file() {
    local file="$1"
    [[ -f "$file" ]] && rm -f "$file"
}

# Función para verificar si un contenedor Docker está activo
verificar_contenedor_activo() {
    local container_name="$1"
    
    log INFO "Verificando estado del contenedor $container_name..."
    
    if docker ps --format "table {{.Names}}" | grep -q "^${container_name}$"; then
        log SUCCESS "Contenedor $container_name está activo"
        return 0
    else
        log ERROR "Contenedor $container_name no está activo o no existe"
        return 1
    fi
}

# Parsear argumentos
parse_arguments() {
    while getopts ":v:r:n:R:p:t:" flag; do
        case "${flag}" in
            v) readonly VERSION=${OPTARG} ;;
            r) readonly V_REPORTS=${OPTARG} ;;
            n) readonly NOMBRE=${OPTARG} ;;
            R) readonly REINICIO=${OPTARG} ;;
            p) readonly PROD=${OPTARG} ;;
            t) readonly TESTE=${OPTARG} ;;
        esac
    done
}

# Mostrar banner
show_banner() {
    cat <<"EOF"

 /$$$$$$$  /$$$$$$$$ /$$$$$$$  /$$        /$$$$$$  /$$     /$$ /$$$$$$$$ /$$$$$$$        /$$   /$$ /$$$$$$$  /$$      /$$
| $$__  $$| $$_____/| $$__  $$| $$       /$$__  $$|  $$   /$$/| $$_____/| $$__  $$      | $$$ | $$| $$__  $$| $$  /$ | $$
| $$  \ $$| $$      | $$  \ $$| $$      | $$  \ $$ \  $$ /$$/ | $$      | $$  \ $$      | $$$$| $$| $$  \ $$| $$ /$$$| $$
| $$  | $$| $$$$$   | $$$$$$$/| $$      | $$  | $$  \  $$$$/  | $$$$$   | $$$$$$$/      | $$ $$ $$| $$$$$$$/| $$/$$ $$ $$
| $$  | $$| $$__/   | $$____/ | $$      | $$  | $$   \  $$/   | $$__/   | $$__  $$      | $$  $$$$| $$____/ | $$$$_  $$$$
| $$  | $$| $$      | $$      | $$      | $$  | $$    | $$    | $$      | $$  \ $$      | $$\  $$$| $$      | $$$/ \  $$$
| $$$$$$$/| $$$$$$$$| $$      | $$$$$$$$|  $$$$$$/    | $$    | $$$$$$$$| $$  | $$      | $$ \  $$| $$      | $$/   \  $$
|_______/ |________/|__/      |________/ \______/     |__/    |________/|__/  |__/      |__/  \__/|__/      |__/     \__/

EOF
}

# Validar parámetros requeridos
validate_parameters() {
    local errors=0
    
    if [[ -z "$NOMBRE" ]]; then
        log ERROR "Parámetro obligatorio -n (nombre) no especificado"
        ((errors++))
    fi
    
    if [[ -z "$VERSION" ]]; then
        log ERROR "Parámetro obligatorio -v (versión) no especificado"
        ((errors++))
    fi
    
    if [[ -z "$PROD" && -z "$TESTE" ]]; then
        log ERROR "Debe especificar al menos un entorno: -p para producción o -t para teste"
        ((errors++))
    fi
    
    return $errors
}

# Descargar archivo (siempre descarga, sin validación de existencia)
download_file() {
    local url="$1"
    local dest_file="$2"
    local description="$3"
    
    log INFO "Descargando $description..."
    
    # Eliminar archivo existente si existe
    cleanup_file "$dest_file"
    
    wget --no-check-certificate -O "$dest_file" "$url" || {
        log ERROR "Error al descargar $description desde $url"
        return 1
    }
    
    log SUCCESS "$description descargado correctamente"
    return 0
}

# Función para descargar archivos NPW (siempre descarga)
descargar_npw() {
    # Limpiar y crear directorio temporal
    cleanup_directory "$TEMP_DIR"
    mkdir -p "$TEMP_DIR" || {
        log ERROR "Error al crear directorio temporal"
        return 1
    }

    local temp_war_scpp="$TEMP_DIR/$ARCHIVO_WAR"
    local temp_zip_front="$TEMP_DIR/$ARCHIVO_FRONTEND"
    local temp_war_reports="$TEMP_DIR/$ARCHIVO_REPORTS"

    # Descargar WAR SCPP
    download_file \
        "$BASE_URL/$APP_NAME/$VERSION/$APP_NAME-$VERSION.war" \
        "$temp_war_scpp" \
        "SCPP WAR" || return 1

    # Descargar ZIP Frontend
    download_file \
        "$BASE_URL/scpp/$VERSION/ProduccionWeb-$VERSION.zip" \
        "$temp_zip_front" \
        "Frontend ZIP" || return 1

    # Descargar Reports si se especificó
    if [[ -n "$V_REPORTS" ]]; then
        download_file \
            "$BASE_URL/$APP_NAME_REPORTS/$V_REPORTS/$APP_NAME_REPORTS-$V_REPORTS.war" \
            "$temp_war_reports" \
            "Reports WAR" || return 1
    fi

    return 0
}

# Función optimizada para reiniciar Docker
reiniciar_docker() {
    local container_name="$1"

    echo "====================================="
    echo "    Reinicio del Contenedor Docker"
    echo "====================================="

    log INFO "Reiniciando contenedor $container_name..."
    
    if docker restart "$container_name" >>"$LOG_FILE" 2>&1; then
        log SUCCESS "Contenedor $container_name reiniciado correctamente"
        return 0
    else
        log ERROR "No se pudo reiniciar el contenedor $container_name"
        return 1
    fi
}

# Función optimizada para deploy del frontend
deploy_front() {
    echo "====================================="
    echo "      Inicio de Deploy Frontend"
    echo "====================================="

    local temp_zip_front="$TEMP_DIR/$ARCHIVO_FRONTEND"
    
    if [[ ! -f "$temp_zip_front" ]]; then
        log ERROR "No se encontró archivo frontend: $temp_zip_front"
        return 1
    fi

    cp "$temp_zip_front" "$ARCHIVO_FRONTEND" || {
        log ERROR "Error al copiar el archivo frontend"
        return 1
    }

    log INFO "Actualizando el frontend..."
    cleanup_directory "$APP_NAME_FRONTEND"

    log INFO "Extrayendo el contenido del archivo"
    if unzip -q "$ARCHIVO_FRONTEND" >>"$LOG_FILE" 2>&1; then
        cleanup_file "$ARCHIVO_FRONTEND"
        log SUCCESS "Actualización del frontend completada"
        return 0
    else
        log ERROR "Error al extraer el archivo frontend"
        return 1
    fi
}

# Función para extraer y modificar WAR
extract_and_modify_war() {
    local war_file="$1"
    local extract_dir="$2"
    local prop_source="$3"
    local prop_dest_name="$4"
    local description="$5"

    # Crear y limpiar directorio de extracción
    cleanup_directory "$extract_dir"
    mkdir -p "$extract_dir" || {
        log ERROR "Error al crear directorio temporal de extracción para $description"
        return 1
    }

    # Extraer WAR
    log INFO "Extrayendo $description..."
    unzip -q "$war_file" -d "$extract_dir" >>"$LOG_FILE" 2>&1 || {
        log ERROR "Error al extraer $description"
        return 1
    }

    # Verificar y reemplazar propiedades
    local prop_dest_dir="$extract_dir/WEB-INF/classes"
    verify_directory "$prop_dest_dir" "directorio WEB-INF/classes en $description" || return 1

    log INFO "Reemplazando $prop_dest_name..."
    cp "$prop_source" "$prop_dest_dir/$prop_dest_name" || {
        log ERROR "Error al reemplazar $prop_dest_name"
        return 1
    }

    return 0
}

# Función para reempaquetar y desplegar WAR
repackage_and_deploy_war() {
    local extract_dir="$1"
    local new_war_name="$2"
    local target_war_path="$3"
    local app_deployed_dir="$4"
    local description="$5"

    # Reempaquetar WAR
    log INFO "Reempaquetando $description..."
    local new_war_path="$TEMP_DIR/new_$new_war_name"
    
    (cd "$extract_dir" && zip -r "$new_war_path" . >>"$LOG_FILE" 2>&1) || {
        log ERROR "Error al reempaquetar $description"
        return 1
    }

    # Limpiar archivos previos
    log INFO "Eliminando archivos previos de $description"
    cleanup_file "$target_war_path"
    cleanup_directory "$app_deployed_dir"

    # Desplegar nuevo WAR
    log INFO "Desplegando nuevo $description..."
    mv "$new_war_path" "$target_war_path" || {
        log ERROR "Error al mover $description reempaquetado"
        return 1
    }

    # Limpiar archivos temporales
    cleanup_directory "$extract_dir"
    log SUCCESS "$description actualizado correctamente"
    return 0
}

# Función optimizada para deploy de SCPP
deploy_scpp() {
    echo "====================================="
    echo "      Inicio de Deploy SCPP"
    echo "====================================="

    local ruta_base="$1"
    local ruta_persistence="$ruta_base/tomcat/persistence"
    local ruta_webapps="$ruta_base/tomcat/webapps"
    local temp_war_scpp="$TEMP_DIR/$ARCHIVO_WAR"
    local temp_extract_dir="$TEMP_DIR/scpp_extract"
    local archivo_prop_origen="$ruta_persistence/$ARCHIVO_PROP"

    # Verificaciones previas
    if [[ ! -f "$archivo_prop_origen" ]]; then
        log ERROR "No se encontró archivo de propiedades SCPP: $archivo_prop_origen"
        return 1
    fi
    
    if [[ ! -f "$temp_war_scpp" ]]; then
        log ERROR "No se encontró archivo WAR SCPP: $temp_war_scpp"
        return 1
    fi

    # Extraer y modificar WAR
    extract_and_modify_war \
        "$temp_war_scpp" \
        "$temp_extract_dir" \
        "$archivo_prop_origen" \
        "$ARCHIVO_PROP" \
        "SCPP WAR" || return 1

    # Reempaquetar y desplegar
    repackage_and_deploy_war \
        "$temp_extract_dir" \
        "$ARCHIVO_WAR" \
        "$ruta_webapps/$ARCHIVO_WAR" \
        "$ruta_webapps/$APP_NAME" \
        "SCPP WAR" || return 1

    return 0
}

# Función optimizada para deploy de reports
deploy_reports() {
    echo "====================================="
    echo "      Inicio de Deploy Reports"
    echo "====================================="

    local ruta_base="$1"
    local ruta_persistence="$ruta_base/tomcat/persistence"
    local ruta_webapps="$ruta_base/tomcat/webapps"
    local temp_war_reports="$TEMP_DIR/$ARCHIVO_REPORTS"
    local temp_extract_dir="$TEMP_DIR/reports_extract"
    local archivo_prop_origen="$ruta_persistence/$ARCHIVO_PROP_REP"

    # Verificaciones previas
    if [[ ! -f "$archivo_prop_origen" ]]; then
        log ERROR "No se encontró archivo de propiedades Reports: $archivo_prop_origen"
        return 1
    fi
    
    if [[ ! -f "$temp_war_reports" ]]; then
        log ERROR "No se encontró archivo WAR Reports: $temp_war_reports"
        return 1
    fi

    # Extraer y modificar WAR
    extract_and_modify_war \
        "$temp_war_reports" \
        "$temp_extract_dir" \
        "$archivo_prop_origen" \
        "$ARCHIVO_PROP_REP" \
        "Reports WAR" || return 1

    # Reempaquetar y desplegar
    repackage_and_deploy_war \
        "$temp_extract_dir" \
        "$ARCHIVO_REPORTS" \
        "$ruta_webapps/$ARCHIVO_REPORTS" \
        "$ruta_webapps/$APP_NAME_REPORTS" \
        "Reports WAR" || return 1

    return 0
}

# Función principal de deploy para un entorno
deploy_environment() {
    local nombre="$1"
    local entorno="$2"
    local entorno_display="$3"
    
    echo ""
    echo "====================================="
    echo " Actualizando el entorno $entorno_display "
    echo "====================================="
    echo ""

    # Buscar carpeta del entorno
    local ruta_base=$(find /docker /home /opt -type d -iname "${nombre}_mrp_${entorno}" 2>/dev/null | head -n 1)
    
    if [[ -z "$ruta_base" ]]; then
        log ERROR "No se encontró carpeta para $nombre en entorno $entorno"
        return 1
    fi

    log INFO "Carpeta encontrada: ${nombre}_mrp_${entorno}"
    log INFO "Ruta: $ruta_base"

    # Verificar que el contenedor está activo 
    local folder_name=$(basename "$ruta_base")
    verificar_contenedor_activo "$folder_name" || {
        log ERROR "No se puede ejecutar deploy: contenedor $folder_name no está activo"
        return 1
    }

    # Cambiar al directorio de webapps
    local webapps_dir="$ruta_base/tomcat/webapps"
    verify_directory "$webapps_dir" "directorio webapps" || return 1
    
    cd "$webapps_dir" || {
        log ERROR "Error al acceder a $webapps_dir"
        return 1
    }

    # Ejecutar deploys en secuencia
    deploy_front || return 1
    deploy_scpp "$ruta_base" || return 1

    # Deploy de reports
    if [[ -n "$V_REPORTS" ]]; then
        deploy_reports "$ruta_base" || return 1
    else
        log INFO "No se especificó versión de reports (-r). Saltando deploy de reports"
    fi

    # Reiniciar Docker 
    if [[ "$REINICIO" == "true" ]]; then
        reiniciar_docker "$folder_name" || return 1
    fi

    return 0
}

# Función principal
main() {
    setup_logging
    parse_arguments "$@"
    show_banner

    # Validar parámetros
    validate_parameters || exit 1

    # Descargar archivos necesarios 
    descargar_npw || {
        log ERROR "Error en la descarga de archivos"
        exit 1
    }

    # Procesar cada nombre especificado
    for nombres in ${NOMBRE//,/ }; do
        # Deploy en producción
        if [[ "$PROD" == "true" ]]; then
            deploy_environment "$nombres" "prod" "Producción" || {
                log ERROR "Error en deploy para $nombres en producción"
                exit 1
            }
        fi

        # Deploy en teste
        if [[ "$TESTE" == "true" ]]; then
            deploy_environment "$nombres" "teste" "Teste" || {
                log ERROR "Error en deploy para $nombres en teste"
                exit 1
            }
        fi
    done

    trap - ERR EXIT  # Desactivar trap de error
    
    # Limpiar archivos temporales al final exitoso
    cleanup_directory "$TEMP_DIR"
    
    log SUCCESS "Deploy completado exitosamente para todos los entornos"
    exit 0
}

# Ejecutar script principal
main "$@"
