#!/bin/bash

#############################################################################################
# Script Name       : archive_script.sh
# Author            : CBillet
# Version           : 1.0
# Created           : 27/12/2024
# Last Modified     : 27/12/2024
#
# Description       :
#   Ce script archive les fichiers créés pendant un mois spécifique, défini dynamiquement à
#   partir de la variable `WAITING_MONTH`. Il s'appuie sur des outils Linux standard
#   (`find`, `tar`, `df`) pour identifier, compresser et, si configuré, supprimer les fichiers archivés.
#
# Fonctionnement principal :
#   - Identification des fichiers :
#     Le script cible exclusivement les fichiers créés pendant un mois complet, basé sur
#     `WAITING_MONTH`, qui indique combien de mois en arrière analyser :
#       * `WAITING_MONTH=0` : Mois en cours.
#       * `WAITING_MONTH=1` : Mois précédent.
#       * `WAITING_MONTH=2` : 2 mois précédent, etc.
#     Exemple :
#       Si `WAITING_MONTH=5` et le script est exécuté le 1er janvier 2024 :
#         - La période analysée sera juin 2023 (du 1er au 30 juin inclus).
#     Pour cela, il utilise `find` avec des bornes temporelles strictes :
#       * `-newermt "$MONTH_FILTER-01"` : Inclut les fichiers créés ou modifiés à partir du 1er jour.
#       * `! -newermt "$MONTH_FILTER-31 23:59:59"` : Exclut les fichiers après le dernier jour.
#     La gestion des mois, y compris leur durée (28, 30, ou 31 jours), est dynamique.
#
#   - Archivage :
#     Les fichiers identifiés sont compressés dans une archive `.tgz` placée dans `ARCHIVE_PATH`.
#     Le script gère les archives incrémentales en ajoutant des suffixes numériques si nécessaire.
#     Cela signifie que le script peux etre executer en avance, ou rejouer durant le même mois (utile notament si WAITING_MONTH est a zero).
#
#   - Vérification des ressources :
#     Avant de créer une archive, le script calcule grosierement la taille totale des fichiers et vérifie
#     que l'espace disque disponible dans `ARCHIVE_PATH` est suffisant.
#
#   - Suppression optionnelle :
#     Si `DELETE_ARCHIVED_FILES=true`, les fichiers archivés sont supprimés après leur compression.
#
# Exemple d'utilisation :
#   - Pour archiver les fichiers créés en juin 2023, exécutez le script en janvier 2024 avec :
#     WAITING_MONTH=5
#
# Configurable Parameters:
#   - SEARCH_DIR: Répertoire source des fichiers.
#   - ARCHIVE_PATH: Répertoire cible des archives.
#   - WAITING_MONTH: Mois ciblé pour le filtrage.
#   - DELETE_ARCHIVED_FILES: Suppression des fichiers archivés (true/false).
#
#############################################################################################


########
## Variables
########
SCRIPT_NAME=$(basename "$0")
SEARCH_DIR="/home/corentin/files"
ARCHIVE_PATH="/home/corentin/archive"
WAITING_MONTH="5"
MONTH_FILTER=$(date +%Y-%m -d "-$WAITING_MONTH month")
BASE_ARCHIVE_NAME="${MONTH_FILTER}-sentinelle"
ARCHIVE_EXTENSION=".tgz"
INDEX_FILENAME="archive_metadata.txt"
LOG_TAG="archive_script"
DELETE_ARCHIVED_FILES="true"  # Variable pour activer/désactiver la suppression des fichiers archivés


########################################################################################################
## Définition des fonctions
########
## Fonction : Récupérer toutes les archives précédentes
########
get_all_previous_archives() {
    local base_name="$1"
    local archive_path="$2"
    local extension="$3"
    local archives=()
    local increment=0

    while true; do
        local candidate
        # verifie si increment = 0
        if [ "$increment" -eq 0 ]; then
            candidate="$archive_path/$base_name$extension"
        else
            candidate="$archive_path/$base_name.$increment$extension"
        fi

        # verifie si le fichier $candidate existe
        if [ -f "$candidate" ]; then
            archives+=("$candidate")
        else
            break
        fi
        increment=$((increment + 1))
    done

    echo "${archives[@]}"
}

########
## Fonction : Vérifier l'espace disque disponible
########
check_disk_space() {
    local required_space="$1"
    local destination_dir="$2"

    local available_space
    available_space=$(df --output=avail "$destination_dir" | tail -n 1)

    # verifie que required_space est > a availabe_space
    if [ "$required_space" -gt "$available_space" ]; then
        logger -t "$LOG_TAG" "ERREUR : Espace disque insuffisant. Requis : ${required_space}KB, disponible : ${available_space}KB."
        echo "ERREUR : Espace disque insuffisant."
        echo "Espace requis : $required_space KB"
        echo "Espace disponible : $available_space KB"
        exit 1
    fi

    logger -t "$LOG_TAG" "Espace disque suffisant : $((available_space / 1024)) Mo disponibles."
    echo "Espace disque suffisant : $((available_space / 1024)) Mo disponibles."
}

########
## Gestion des erreurs
########
handle_error() {
    logger -t "$LOG_TAG" "ERREUR : Une erreur s'est produite lors de l'exécution du script $SCRIPT_NAME."
    echo "ERREUR : Une erreur s'est produite. Consultez les logs pour plus de détails."
    exit 1
}

trap handle_error ERR

########################################################################################################
## Corp du script
########
## Début du script
########
logger -t "$LOG_TAG" "DÉMARRAGE : Le script $SCRIPT_NAME a commencé."
echo "DÉMARRAGE : Le script $SCRIPT_NAME a commencé."
cat <<EOF

Le répertoire de recherche est défini comme : $SEARCH_DIR
Les résultats seront stockés dans l'archive située à : $ARCHIVE_PATH

EOF

logger -t "$LOG_TAG" "INFORMATION : Recherche des fichiers à archiver dans le répertoire $SEARCH_DIR pour le mois $MONTH_FILTER."

########
## Préparer l'archivage
########
PREVIOUS_ARCHIVES=($(get_all_previous_archives "$BASE_ARCHIVE_NAME" "$ARCHIVE_PATH" "$ARCHIVE_EXTENSION"))

# verifie que le tableau est vide ( aucun input dans l'array )
if [ ${#PREVIOUS_ARCHIVES[@]} -eq 0 ]; then
    NEXT_ARCHIVE="$ARCHIVE_PATH/$BASE_ARCHIVE_NAME$ARCHIVE_EXTENSION"
else
    NEXT_ARCHIVE="$ARCHIVE_PATH/$BASE_ARCHIVE_NAME.${#PREVIOUS_ARCHIVES[@]}$ARCHIVE_EXTENSION"
fi

DATE=$(date +"%Y-%m-%d_%H-%M-%S")

logger -t "$LOG_TAG" "Archives précédentes trouvées :"
for archive in "${PREVIOUS_ARCHIVES[@]}"; do
    logger -t "$LOG_TAG" " - $archive"
done

logger -t "$LOG_TAG" "Prochaine archive à créer : $NEXT_ARCHIVE"
echo "Prochaine archive : $NEXT_ARCHIVE"

########
## Recherche des fichiers à inclure
########
SEARCH_FILES=$(find "$SEARCH_DIR" -type f -newermt "$MONTH_FILTER-01" ! -newermt "$MONTH_FILTER-31 23:59:59" 2>/dev/null)

# verifie si search_file est vide
if [ -z "$SEARCH_FILES" ]; then
    logger -t "$LOG_TAG" "Aucun fichier trouvé correspondant aux critères pour le mois $MONTH_FILTER."
    echo "Aucun fichier trouvé pour le mois $MONTH_FILTER."
    exit 0
fi

NUM_FILES=$(echo "$SEARCH_FILES" | wc -l)
logger -t "$LOG_TAG" "Nombre total de fichiers trouvés : $NUM_FILES"
echo "Nombre total de fichiers trouvés : $NUM_FILES"

echo "Liste des fichiers trouvés :"
logger -t "$LOG_TAG" "Liste des fichiers trouvés :"
for file in $SEARCH_FILES; do
    echo " - $file"
    logger -t "$LOG_TAG" " - $file"
done

########
## Création des métadonnées pour l'archive
########
INDEX_CONTENT="Date de création : $DATE\n"
INDEX_CONTENT+="Archives précédentes incluses :\n"
for archive in "${PREVIOUS_ARCHIVES[@]}"; do
    INDEX_CONTENT+="$archive\n"
done
INDEX_CONTENT+="Fichiers inclus dans cette archive :\n$SEARCH_FILES\n"

########
## Calcul de la taille estimée de l'archive
########
REQUIRED_SPACE=0
for file in $SEARCH_FILES; do
    REQUIRED_SPACE=$((REQUIRED_SPACE + $(du -k "$file" | cut -f1)))
done

for archive in "${PREVIOUS_ARCHIVES[@]}"; do
    REQUIRED_SPACE=$((REQUIRED_SPACE + $(du -k "$archive" | cut -f1)))
done

METADATA_SIZE=$(echo -e "$INDEX_CONTENT" | wc -c)
REQUIRED_SPACE=$((REQUIRED_SPACE + METADATA_SIZE / 1024 + 1))

check_disk_space "$REQUIRED_SPACE" "$ARCHIVE_PATH"

logger -t "$LOG_TAG" "Création de l'archive estimée : $NEXT_ARCHIVE avec une taille de $((REQUIRED_SPACE / 1024)) Mo."

########
## Création de l'archive
########
TMP_DIR=$(mktemp -d)
echo -e "$INDEX_CONTENT" > "$TMP_DIR/$INDEX_FILENAME"

TAR_COMMAND=(tar -czf "$NEXT_ARCHIVE")
for archive in "${PREVIOUS_ARCHIVES[@]}"; do
    TAR_COMMAND+=(-C "$(dirname "$archive")" "$(basename "$archive")")
done
TAR_COMMAND+=(-C "$SEARCH_DIR" $(echo "$SEARCH_FILES" | tr '\n' ' '))
TAR_COMMAND+=(-C "$TMP_DIR" "$INDEX_FILENAME")

# verifie si la commande stocké dans tar_command échoue
# TAR_command[@] : Cette syntaxe permet de dérouler tous les éléments du tableau TAR_COMMAND et de les exécuter comme une commande
if ! "${TAR_COMMAND[@]}"; then
    handle_error
fi

REAL_ARCHIVE_SIZE=$(du -m "$NEXT_ARCHIVE" | cut -f1)
logger -t "$LOG_TAG" "Taille réelle de l'archive créée : ${REAL_ARCHIVE_SIZE} Mo."
echo "Taille réelle de l'archive créée : ${REAL_ARCHIVE_SIZE} Mo."

########
## Suppression des fichiers archivés (optionnelle)
########
# verifie si la variable delete_archived_files = true
if [ "$DELETE_ARCHIVED_FILES" = "true" ]; then
    logger -t "$LOG_TAG" "Suppression des fichiers archivés activée."
    for file in $SEARCH_FILES; do
        # execute le rm et verifie si la commande reussi ou échoue
        if rm "$file"; then
            logger -t "$LOG_TAG" "Fichier supprimé : $file"
            echo "Fichier supprimé : $file"
        else
            logger -t "$LOG_TAG" "ERREUR : Échec de la suppression du fichier $file"
            echo "ERREUR : Échec de la suppression du fichier $file"
        fi
    done
else
    logger -t "$LOG_TAG" "Suppression des fichiers archivés désactivée. Les fichiers originaux sont conservés."
    echo "Suppression désactivée. Les fichiers originaux sont conservés."
fi

########
## Fin du script
########
FINAL_AVAILABLE_SPACE=$(df --output=avail "$ARCHIVE_PATH" | tail -n 1)
logger -t "$LOG_TAG" "Espace disque restant après exécution : $((FINAL_AVAILABLE_SPACE / 1024)) Mo."
echo "Espace disque restant après exécution : $((FINAL_AVAILABLE_SPACE / 1024)) Mo."

logger -t "$LOG_TAG" "TERMINÉ : Le script $SCRIPT_NAME s'est terminé avec succès. Archive créée : $NEXT_ARCHIVE"
echo "TERMINÉ : Le script $SCRIPT_NAME s'est terminé avec succès. Archive créée : $NEXT_ARCHIVE"
