#!/bin/bash

# backup-gitea.sh - Backup Gitea, Postgres, and Runner
# Enhanced for NAS support and Runner integration

set -e

# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# ==========================================
# 1. CONFIGURATION
# ==========================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

COMPOSE_DIR="/home/acedanger/docker/gitea" 

BACKUP_DIR="/home/acedanger/backups/gitea"
NAS_DIR="/mnt/share/media/backups/gitea"
COMPOSE_FILE="$COMPOSE_DIR/docker-compose.yml"
LOG_FILE="$SCRIPT_DIR/logs/gitea-backup.log"
DATE=$(date +%Y%m%d_%H%M%S)

# Ensure directories exist
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_DIR"

# Load .env variables from the COMPOSE_DIR to ensure DB credentials match
if [ -f "$COMPOSE_DIR/.env" ]; then
    export $(grep -v '^#' "$COMPOSE_DIR/.env" | xargs)
fi

# Logging function (Fixed to interpret colors correctly)
log() {
    # Print to console with colors (interpreting escapes with -e)
    echo -e "$(date '+%Y-%m-%d %H:%M:%S') - $1"
    # Strip colors for the log file to keep it clean
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sed 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE"
}

# Display usage information
usage() {
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Backup Gitea data, Runner, and PostgreSQL database"
    echo "Options:"
    echo "  -h, --help              Show this help message"
    echo "  -l, --list              List available local backups"
    echo "  -n, --no-nas            Skip copying to NAS (Local only)"
    echo ""
}

# Check dependencies
check_dependencies() {
    if ! command -v docker &> /dev/null; then
        log "${RED}Error: docker is not installed.${NC}"
        exit 1
    fi
    
    # Verify the compose file exists where we expect it
    if [ ! -f "$COMPOSE_FILE" ]; then
        log "${RED}Error: Docker compose file not found at: $COMPOSE_FILE${NC}"
        log "${YELLOW}Please update the COMPOSE_DIR variable in this script.${NC}"
        exit 1
    fi
}

# List available backups
list_backups() {
    echo -e "${BLUE}=== Available Gitea Backups ===${NC}"
    ls -lh "$BACKUP_DIR"/*.tar.gz 2>/dev/null || echo "No backups found."
}

# ==========================================
# 2. BACKUP LOGIC
# ==========================================
perform_backup() {
    local SKIP_NAS=$1
    
    log "Starting backup process..."

    # Switch context to the directory where Gitea is actually running
    cd "$COMPOSE_DIR" || { log "${RED}Could not change to directory $COMPOSE_DIR${NC}"; exit 1; }

    # PRE-FLIGHT CHECK: Is the DB actually running?
    if ! docker compose ps --services --filter "status=running" | grep -q "db"; then
        log "${RED}CRITICAL ERROR: The 'db' service is not running in $COMPOSE_DIR${NC}"
        log "${YELLOW}Docker sees these running services:$(docker compose ps --services --filter "status=running" | xargs)${NC}"
        log "Aborting backup to prevent empty files."
        exit 1
    fi

    # Create a temporary staging directory for this specific backup
    TEMP_BACKUP_PATH="$BACKUP_DIR/temp_$DATE"
    mkdir -p "$TEMP_BACKUP_PATH"

    # 1. Backup Database
    log "Step 1/5: Dumping PostgreSQL database..."
    # Using -T to disable TTY allocation (fixes some cron issues)
    if docker compose exec -T db pg_dump -U "${POSTGRES_USER:-gitea}" "${POSTGRES_DB:-gitea}" > "$TEMP_BACKUP_PATH/database.sql"; then
        echo -e "${GREEN}Database dump successful.${NC}"
    else
        log "${RED}Database dump failed!${NC}"
        rm -rf "$TEMP_BACKUP_PATH"
        exit 1
    fi

    # 2. Backup Gitea Data
    log "Step 2/5: Backing up Gitea data volume..."
    docker run --rm \
        --volumes-from gitea \
        -v "$TEMP_BACKUP_PATH":/backup \
        alpine tar czf /backup/gitea_data.tar.gz -C /data .

    # 3. Backup Runner Data
    log "Step 3/5: Backing up Runner data..."
    # Check if runner exists before backing up to avoid errors if you removed it
    if docker compose ps --services | grep -q "runner"; then
        docker run --rm \
            --volumes-from gitea-runner \
            -v "$TEMP_BACKUP_PATH":/backup \
            alpine tar czf /backup/runner_data.tar.gz -C /data .
    else
        log "${YELLOW}Runner service not found, skipping runner backup.${NC}"
    fi

    # 4. Config Files & Restore Script
    log "Step 4/5: Archiving configurations and generating restore script..."
    cp "$COMPOSE_FILE" "$TEMP_BACKUP_PATH/"
    [ -f ".env" ] && cp ".env" "$TEMP_BACKUP_PATH/"

    # Generate the Restore Script inside the backup folder
    create_restore_script "$TEMP_BACKUP_PATH"

    # 5. Final Archive Creation
    log "Step 5/5: Compressing full backup..."
    FINAL_ARCHIVE_NAME="gitea_backup_$DATE.tar.gz"
    
    # Tar the temp folder into one final file
    tar -czf "$BACKUP_DIR/$FINAL_ARCHIVE_NAME" -C "$TEMP_BACKUP_PATH" .
    
    # Remove temp folder
    rm -rf "$TEMP_BACKUP_PATH"
    
    log "${GREEN}Local Backup completed: $BACKUP_DIR/$FINAL_ARCHIVE_NAME${NC}"

    # 6. NAS Transfer
    if [[ "$SKIP_NAS" != "true" ]]; then
        if [ -d "$NAS_DIR" ]; then
            log "Copying to NAS ($NAS_DIR)..."
            cp "$BACKUP_DIR/$FINAL_ARCHIVE_NAME" "$NAS_DIR/"
            if [ $? -eq 0 ]; then
                 log "${GREEN}NAS Copy Successful.${NC}"
            else
                 log "${RED}NAS Copy Failed. Check permissions on $NAS_DIR${NC}"
            fi
        else
            log "${YELLOW}NAS Directory $NAS_DIR not found. Skipping NAS copy.${NC}"
        fi
    else
        log "NAS copy skipped by user request."
    fi

    # 7. Cleanup Old Local Backups (Keep 7 Days)
    find "$BACKUP_DIR" -name "gitea_backup_*.tar.gz" -mtime +7 -exec rm {} \;
    log "Cleanup of old local backups complete."
}

# Function to generate the restore script
create_restore_script() {
    local TARGET_DIR=$1
    cat > "$TARGET_DIR/restore.sh" << 'EOF'
#!/bin/bash
# RESTORE SCRIPT
echo "WARNING: This will overwrite your current Gitea/DB/Runner data."
read -p "Are you sure? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1; fi

docker compose down

echo "Restoring Database Volume..."
docker compose up -d db
echo "Waiting for DB to initialize..."
sleep 15
cat database.sql | docker compose exec -T db psql -U ${POSTGRES_USER:-gitea} -d ${POSTGRES_DB:-gitea}

echo "Restoring Gitea Files..."
docker run --rm --volumes-from gitea -v $(pwd):/backup alpine tar xzf /backup/gitea_data.tar.gz -C /data

echo "Restoring Runner Files..."
docker run --rm --volumes-from gitea-runner -v $(pwd):/backup alpine tar xzf /backup/runner_data.tar.gz -C /data

echo "Restarting stack..."
docker compose up -d
echo "Restore Complete."
EOF
    chmod +x "$TARGET_DIR/restore.sh"
}

# ==========================================
# 3. EXECUTION FLOW
# ==========================================

check_dependencies

# Parse Arguments
if [ $# -eq 0 ]; then
    perform_backup "false"
    exit 0
fi

while [[ "$#" -gt 0 ]]; do
    case $1 in
        -h|--help) usage; exit 0 ;;
        -l|--list) list_backups; exit 0 ;;
        -n|--no-nas) perform_backup "true"; exit 0 ;;
        *) echo "Unknown parameter: $1"; usage; exit 1 ;;
    esac
    shift
done