#!/bin/bash

# Load environment variables from .env file
if [ -f .env ]; then
    # Read each line from .env and export variables
    while IFS= read -r line || [[ -n "$line" ]]; do
        # Skip comments and empty lines
        [[ $line =~ ^#.*$ ]] && continue
        [[ -z "$line" ]] && continue
        
        # Export the variable
        export "$line"
    done < .env
else
    echo "Error: .env file not found"
    exit 1
fi

# Variables (now using environment variables with defaults)
MYSQL_USER="admin"
MYSQL_PASSWORD=${MYSQL_ADMIN_PASSWORD}
BACKUP_DIR="$(pwd)/backups"
REMOTE_HOST="${BACKUP_SERVER_HOST}"  # Remote server hostname/IP
REMOTE_USER="${BACKUP_SERVER_USER}"                     # Remote server username
REMOTE_BACKUP_DIR="${BACKUP_SERVER_PATH}"        # Remote server backup path
TEMP_DIR="$BACKUP_DIR/tmp"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
MODE=""
HOURLY_RETENTION=4
DAILY_RETENTION=3
WEEKLY_RETENTION=1
MIN_SPACE=20  # Minimum space in GB
DB_CONTAINER="mailserver_db"

# Function to display usage
function usage() {
  echo "Usage: $0 --hourly | --daily | --weekly"
  exit 1
}

# Function to check available space and cleanup if necessary
function check_and_cleanup_space() {
    local available_space=$(df -BG "$REMOTE_BACKUP_DIR" | awk 'NR==2 {gsub("G","",$4); print $4}')
    
    if [ "$available_space" -le "$MIN_SPACE" ]; then
        echo "Available space ($available_space GB) is less than minimum required ($MIN_SPACE GB)"
        echo "Starting cleanup..."
        
        while [ "$available_space" -le "$MIN_SPACE" ]; do
            # Find oldest backup file
            oldest_file=$(find "$REMOTE_BACKUP_DIR" -type f -name "*.zip" -printf '%T+ %p\n' | sort | head -n 1 | awk '{print $2}')
            
            if [ -z "$oldest_file" ]; then
                echo "No more files to delete!"
                break
            fi
            
            # Get file size before deletion for logging
            file_size=$(du -h "$oldest_file" | cut -f1)
            
            # Delete the file
            rm -f "$oldest_file"
            echo "Deleted old backup: $oldest_file (Size: $file_size)"
            
            # Recalculate available space
            available_space=$(df -BG "$REMOTE_BACKUP_DIR" | awk 'NR==2 {gsub("G","",$4); print $4}')
        done
        
        echo "Cleanup complete. Available space: $available_space GB"
    fi
}

echo "##########################"
echo "Starting backup..."
echo "##########################"
echo ""

# Check if the correct parameter is passed
if [[ "$1" == "--hourly" ]]; then
  MODE="hourly"
elif [[ "$1" == "--daily" ]]; then
  MODE="daily"
elif [[ "$1" == "--weekly" ]]; then
  MODE="weekly"
else
  usage
fi
echo "##########################"
echo "Mode: $MODE"
echo "##########################"
echo ""

echo "##########################"
echo "Creating backup directories..."
echo "##########################"
echo ""

# Create backup and temp directories if they don't exist
mkdir -p "$BACKUP_DIR"
mkdir -p "$TEMP_DIR"
mkdir -p "/var/log/backup"

# Backup all MySQL databases
echo "##########################"
echo "Backing up MySQL databases..."
echo "##########################"
echo ""

# Test database connection first
if ! docker exec -i $DB_CONTAINER mariadb -u $MYSQL_USER -p${MYSQL_PASSWORD} -e "SELECT 1;" >/dev/null 2>&1; then
    echo "Error: Cannot connect to MySQL database. Please check credentials."
    echo "Container: $DB_CONTAINER"
    echo "User: $MYSQL_USER"
    echo "Password being used: ${MYSQL_PASSWORD}"
    exit 1
fi

# Get databases list without using -it flag (which requires terminal)
databases=$(docker exec -i $DB_CONTAINER mariadb -u $MYSQL_USER -p${MYSQL_PASSWORD} -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")

for db in $databases; do
    echo "Backing up database: $db"
    docker exec -i $DB_CONTAINER mariadb-dump -u $MYSQL_USER -p${MYSQL_PASSWORD} --databases "$db" > "$TEMP_DIR/${db}.sql"
    if [ $? -eq 0 ]; then
        zip -j "$TEMP_DIR/${db}.sql.zip" "$TEMP_DIR/${db}.sql"
        rm "$TEMP_DIR/${db}.sql"
    else
        echo "Error backing up database: $db"
    fi
done

DIRECTORIES_TO_BACKUP=(
  "/opt/2weekmail"
)

for dir in "${DIRECTORIES_TO_BACKUP[@]}"; do
  DIR_NAME=$(basename "$dir")
  zip -r "$TEMP_DIR/${DIR_NAME}_${MODE}_$TIMESTAMP.zip" "$dir" -x "*/node_modules/*" "*/backups/*"
done

# Compress all SQL and directories into a single zip file
echo "##########################"
echo "Compressing backup files..."
echo "##########################"
echo ""

FINAL_BACKUP_FILE="$BACKUP_DIR/${MODE}_backup_$TIMESTAMP.zip"
find "$TEMP_DIR" -name "*.zip" | while read file; do
  zip -ur "$FINAL_BACKUP_FILE" "$file"
done

# Clean up temporary files
rm -rf "$TEMP_DIR"

echo "##########################"
echo "Backup complete: $FINAL_BACKUP_FILE"
echo "##########################"
echo ""

function apply_retention() {
  backup_type=$1
  retention_count=$2

  # Find all backup files of the specified type, sort them by modification time, and keep the newest
  backups=($(ls -t $BACKUP_DIR/${backup_type}_backup_*.zip))

  # If the number of backups exceeds the retention limit, delete the older ones
  if [ ${#backups[@]} -gt $retention_count ]; then
    delete_count=$((${#backups[@]} - $retention_count))
    for (( i=$retention_count; i<${#backups[@]}; i++ )); do
      rm -f "${backups[$i]}"
      echo "Deleted old $backup_type backup: ${backups[$i]}"
    done
  fi
}

echo "##########################"
echo "Applying retention policy..."
echo "##########################"
echo ""

# Apply retention policy
if [[ "$MODE" == "hourly" ]]; then
  apply_retention "hourly" $HOURLY_RETENTION
elif [[ "$MODE" == "daily" ]]; then
  apply_retention "daily" $DAILY_RETENTION
elif [[ "$MODE" == "weekly" ]]; then
  apply_retention "weekly" $WEEKLY_RETENTION
fi

echo "Retention policy applied: $MODE backups cleaned."
echo "##########################"
echo "Backup cleanup complete."
echo "##########################"
echo ""

echo "##########################"
echo "Checking remote backup space..."
echo "##########################"
echo ""

# Check and cleanup space before copying new backup
check_and_cleanup_space

# Use rsync to copy the backup
if ! ssh -p "$BACKUP_SERVER_PORT" "${REMOTE_USER}@${REMOTE_HOST}" exit 2>/dev/null; then
    echo "Error: Cannot connect to remote backup server"
    echo "Backup file is saved locally at: $FINAL_BACKUP_FILE"
    exit 1
fi

rsync -av --progress -e "ssh -p $BACKUP_SERVER_PORT" "$FINAL_BACKUP_FILE" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_BACKUP_DIR}/"

echo "##########################"
echo "Remote backup complete"
echo "##########################"
echo ""