#!/bin/bash

database=$1

root_dir="/root/Desktop/Work4all-system"

log_message() {
    echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1"
    echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> $root_dir/logs.txt
}

cd  $root_dir

mssql_enabled=$(jq '.containers.mssql.enabled' config.json)
backup_enabled=$(jq '.containers.mssql.backups.enabled' config.json)

if [ "$mssql_enabled" != "true" ]; then
    exit 0
fi

if [ "$backup_enabled" != "true" ]; then
    exit 0
fi

echo "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" >> $root_dir/logs.txt
log_message "[Starting MSSQL Backup Process]"

customer_number=$(jq '.general.customer_number' config.json)
apikey=$(jq -r '.general.apikey' config.json)
url=$(jq -r '.general.update_url' config.json)

exit_and_alert() {
    curl -X POST https://api.${url}/backup_failure -H "Content-Type: application/json" -d "{ \"number\" : \"${customer_number}\", \"apikey\" : \"${apikey}\" }"
    exit 1
}

backup_path=$(jq -r '.containers.mssql.volumes.backup.path' config.json)

log_message "Retrieving tenant names..."

tenants_string=$(docker exec mssql bash -c '/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -h -1 -C -Q "SET NOCOUNT ON; SELECT name FROM sys.databases WHERE name LIKE '\''Work%'\'';"' | tr -s ' ' '\n')

IFS=$'\n' read -r -d '' -a tenants <<< "$tenants_string"$'\0'

# validating tenant names
for tenant in "${tenants[@]}"; do
    if [[ ! "$tenant" =~ ^[A-Za-z0-9_-]+$ ]]; then
        log_message "Tenant name contains invalid characters: [$tenant]"
        exit_and_alert
    fi
done


# checking if all tenants mentioned in the json file actually exist

for tenant in "${tenants[@]}"; do
    log_message "checking if $tenant exists: "
    query="SELECT CASE WHEN EXISTS (SELECT 1 FROM sys.databases WHERE name = '$tenant') THEN 1 ELSE 0 END;"
    tenant_exists=$(docker exec -i mssql bash -c "/opt/mssql-tools18/bin/sqlcmd -U sa -P \"\$SA_PASSWORD\" -b -C -h -1 -s \"|\" -Q \"SET NOCOUNT ON; $query\" | awk -F'|' '{print \$1}' | sed '/^$/d'")
    tenant_exists="${tenant_exists// /}" # stripping
    if [ "$tenant_exists" != "1" ]; then
        log_message "tenant $tenant does not exist..."
        log_message "[$tenant_exists]"
        log_message "Exitting..."
        exit_and_alert
    fi
done

# checking if backup sizes are greater than the available space in the backup volume
backup_volume_space=$(df --output=avail -B1 $backup_path | tail -n 1)

declare -i total_tenant_sizes=0

for tenant in "${tenants[@]}"; do
    query="SELECT SUM(CAST(size AS BIGINT)) * 8 * 1024 AS SizeBytes FROM sys.master_files WHERE database_id = DB_ID('$tenant') GROUP BY database_id;"
    tenant_size=$(docker exec -i mssql bash -c "/opt/mssql-tools18/bin/sqlcmd -U sa -P \"\$SA_PASSWORD\" -b -C -h -1 -s \"|\" -Q \"SET NOCOUNT ON; $query\" | awk -F'|' '{print \$1}' | sed '/^$/d'")
    log_message "tenant size for ${tenant} (Bytes): ${tenant_size}"
    total_tenant_sizes=$(($total_tenant_sizes + $tenant_size))
done

log_message "Size of tenants in total (Bytes): $total_tenant_sizes"
log_message "Size of the backup volume (Bytes): $backup_volume_space"

if [ $backup_volume_space -le $total_tenant_sizes ]; then
    log_message "Not enough space left on the device to generate a backup $backup_volume_space"
    log_message "Exitting"
    exit_and_alert
fi

log_message "Enough storage space for the backup, Proceeding..."

declare -i failed=0


for tenant in "${tenants[@]}"; do
    log_message "restoring tenant $tenant"
    docker exec mssql bash -c "
        database='$tenant' &&
        now=\$(date +%Y-%m-%d_%Hh%Mm%Ssec) &&
        /opt/mssql-tools18/bin/sqlcmd -U sa -P \"\$SA_PASSWORD\" -e -b -C -Q \"
            BACKUP DATABASE [\$database]
            TO DISK = N'/var/opt/mssql/backup/\$database-\$now.bak'
            WITH NOFORMAT, NOINIT, NAME = '\${database}Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10;
        \"
    "
    exit_code=$?
    failed=$(($failed + $exit_code))
    if [ "$exit_code" != "0" ]; then
        log_message "BACKUP FAILURE FOR [$tenant]"
    fi
done

if [ "$failed" != "0" ]; then
    exit_and_alert
fi

# remove old *.bak files

keep=1 # keeping only x copy of the set

cd $backup_path

for tenant in "${tenants[@]}"; do
    files=$(find . -maxdepth 1 -type f -name "${tenant}-*.bak" -printf "%T@ %p\n" | sort -n | cut -d" " -f2-) &&
    count=$(echo "$files" | wc -l) &&
    if [ "$count" -gt "$keep" ]; then
        echo "Deleting files for tenant $tenant... found $count of them" &&
        echo "$files" | head -n -"$keep" | xargs rm -f;
    else
        echo "No need to delete backup copies for $tenant";
    fi;
done

cd $root_dir

log_message "Done"