#!/bin/bash

# Simple script to restore classes and groups
# Copyright (C) 2026 FUSS Project <info@fuss.bz.it>
# Author: Claudio Cavalli <ccavalli@fuss.bz.it>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

exec > >(tee fuss_full_restore.log) 2>&1

# --- CONFIGURAZIONE ---
LDIF_FILE="ldap-dump.ldif"
CLASS_CSV="classes_mapping.csv"
GROUP_CSV="groups_mapping.csv"
SEARCH_ROOT="/home/primaria/alunni"
GRUPPO_PRIMARIO="studenti"
CARTELLA_COMUNE="00-Comune"
CTIME_THRESHOLD_HOURS=48
DRY_RUN=true

# --- FUNZIONI ---

get_confirmation() {
    while true; do
        echo -e "$1\n(yes/no): "
        read choice
        case $choice in
            [Yy]* ) return 0;;
            [Nn]* ) return 1;;
            * ) echo "Please answer 'yes' or 'no'.";;
        esac
    done
}

get_ldap_base() {
    ldapsearch -Y EXTERNAL -H ldapi:/// -s base -b '' namingContexts 2>/dev/null | grep "namingContexts:" | awk '{print $2}' || echo "dc=fusslab,dc=blz"
}

# --- CONFIGURAZIONE INTERATTIVA ---

if [[ $EUID -ne 0 ]]; then
   echo "Questo script deve essere eseguito come root"
   exit 1
fi

echo "--- CONFIGURAZIONE RIPRISTINO FUSS ---"

if get_confirmation "Il gruppo primario degli utenti da ripristinare è \"$GRUPPO_PRIMARIO\"?"; then
    echo "OK: $GRUPPO_PRIMARIO"
else
    echo "Inserisci il gruppo primario degli utenti da ripristinare:"
    read GRUPPO_PRIMARIO
    if get_confirmation "Confermi che il gruppo primario è \"$GRUPPO_PRIMARIO\"?"; then
        echo "OK"
    else
        exit 1
    fi
fi

if get_confirmation "Le classi hanno una CARTELLA_COMUNE?"; then
    if get_confirmation "Il nome della cartella comune è \"$CARTELLA_COMUNE\"?"; then
        echo "OK"
    else
        echo "Inserisci il nome della cartella comune:"
        read CARTELLA_COMUNE
        if get_confirmation "Confermi che il nome della cartella comune è \"$CARTELLA_COMUNE\"?"; then
            echo "OK"
        else
            echo "⚠️ Non hai scelto il nome!"
            exit 1
        fi
    fi
else
    CARTELLA_COMUNE=""
fi

if ! get_confirmation "Il percorso di ricerca delle home è \"$SEARCH_ROOT\"?"; then
    echo "Inserisci il percorso di ricerca home:"
    read SEARCH_ROOT
fi

LDAP_BASE=$(get_ldap_base)
if ! get_confirmation "La LDAP Base DN rilevata è \"$LDAP_BASE\"?"; then
    echo "Inserisci la LDAP Base DN corretta:"
    read LDAP_BASE
fi

if get_confirmation "Vuoi eseguire una SIMULAZIONE (Dry-run)?"; then
    DRY_RUN=true
    echo "🔍 Modalità SIMULAZIONE attiva."
else
    if get_confirmation "⚠️ CONFERMI DI VOLER PROCEDERE AL RIPRISTINO REALE?"; then
        DRY_RUN=false
        echo "🚀 Modalità REALE attiva."
    else
        exit 0
    fi
fi

# --- RIPRISTINO LDAP ---

echo -e "\n--- 1. Ripristino LDAP ---"
if [ "$DRY_RUN" = false ]; then
    if [ ! -f "$LDIF_FILE" ]; then
        echo "❌ Errore: $LDIF_FILE non trovato."
        exit 1
    fi
    
    echo "Creazione backup di emergenza..."
    slapcat -l "emerg_backup_$(date +%s).ldif"
    
    echo "Fermo i servizi e svuoto il database..."
    systemctl stop slapd octofussd
    rm -rf /var/lib/ldap/*
    
    echo "Importazione dati da $LDIF_FILE..."
    slapadd -l "$LDIF_FILE"
    chown -R openldap:openldap /var/lib/ldap/
    systemctl start slapd
    echo "Attesa inizializzazione LDAP (5 sec)..."
    sleep 5
else
    echo "[Simulazione] LDAP non verrà toccato."
fi

# --- RECUPERO DATI E SINCRONIZZAZIONE HOMES ---

echo -e "\n--- 2. Ripristino Home Utenti ---"

# Estraiamo gli utenti e le loro home dal database LDAP (appena ripristinato o corrente)
# Usiamo un trucco awk per unire le righe LDIF che a volte vanno a capo
USERS_DATA=$(ldapsearch -x -H ldapi:/// -LLL -b "$LDAP_BASE" "(objectClass=posixAccount)" uid homeDirectory | awk '/^uid: / {u=$2} /^homeDirectory: / {print u " " $2}')

MOVED_H=0
while read -r UID_USER TARGET_HOME; do
    [ -z "$UID_USER" ] && continue
    
    # Se la home esiste già nella posizione corretta, saltiamo
    if [ -d "$TARGET_HOME" ]; then
        continue
    fi
    
    # Cerchiamo la cartella sul disco
    FOUND_PATH=$(find "$SEARCH_ROOT" -maxdepth 3 -type d -name "$UID_USER" -print -quit)
    
    if [ -n "$FOUND_PATH" ]; then
        echo "👤 $UID_USER: $FOUND_PATH -> $TARGET_HOME"
        if [ "$DRY_RUN" = false ]; then
            mkdir -p "$(dirname "$TARGET_HOME")"
            mv "$FOUND_PATH" "$TARGET_HOME"
        fi
        ((MOVED_H++))
    fi
done <<< "$USERS_DATA"

# RIPRISTINO CARTELLE COMUNI ---

MOVED_C=0
if [ -n "$CARTELLA_COMUNE" ]; then
    echo -e "\n--- 3. Ripristino Cartelle Comuni ---"
    
    # Carichiamo i mapping inversi (Nuovo -> Vecchio)
    declare -A rev_classi
    if [ -f "$CLASS_CSV" ]; then
        while IFS=, read -r OLD NEW; do
            OLD=$(echo "$OLD" | tr -d '\r' | xargs)
            NEW=$(echo "$NEW" | tr -d '\r' | xargs)
            rev_classi["$NEW"]="$OLD"
        done < "$CLASS_CSV"
    fi

    declare -A rev_groups
    if [ -f "$GROUP_CSV" ]; then
        while IFS=, read -r OLD NEW; do
            OLD=$(echo "$OLD" | tr -d '\r' | xargs)
            NEW=$(echo "$NEW" | tr -d '\r' | xargs)
            rev_groups["$NEW"]="$OLD"
        done < "$GROUP_CSV"
    fi

    # Scansione per le cartelle comuni
    while read -r C_PATH; do
        PARENT_DIR=$(dirname "$C_PATH")
        
        # Filtro STAT: verifichiamo se mossa di recente
        # Calcoliamo la differenza tra ctime e mtime
        CTIME=$(stat -c %Z "$C_PATH")
        MTIME=$(stat -c %Y "$C_PATH")
        NOW=$(date +%s)
        DIFF_CTIME=$((NOW - CTIME))
        THRESHOLD=$((CTIME_THRESHOLD_HOURS * 3600))
        
        if [ "$CTIME" -gt "$MTIME" ] && [ "$DIFF_CTIME" -lt "$THRESHOLD" ]; then
            TARGET_PARENT="${rev_classi[$PARENT_DIR]}"
            
            if [ -n "$TARGET_PARENT" ]; then
                TARGET_C="$TARGET_PARENT/$CARTELLA_COMUNE"
                if [ ! -d "$TARGET_C" ]; then
                    # Identificazione vecchio gruppo
                    GRP_NOW=$(stat -c %G "$C_PATH")
                    OLD_GRP="${rev_groups[$GRP_NOW]}"
                    [ -z "$OLD_GRP" ] && OLD_GRP=$GRP_NOW
                    
                    echo "📂 COMUNE: $PARENT_DIR -> $TARGET_PARENT"
                    if [ "$DRY_RUN" = false ]; then
                        mkdir -p "$TARGET_PARENT"
                        mv "$C_PATH" "$TARGET_C"
                        chgrp -R "$OLD_GRP" "$TARGET_C"
                    fi
                    ((MOVED_C++))
                fi
            fi
        fi
    done < <(find "$SEARCH_ROOT" -type d -name "$CARTELLA_COMUNE")
fi

if [ "$DRY_RUN" = false ]; then
    systemctl start octofussd
fi

echo -e "\nRIPRISTINO CONCLUSO. Home: $MOVED_H, Comuni: $MOVED_C (DRY_RUN: $DRY_RUN)"
