#!/bin/bash

# ThrillWiki Deployment Script
# Deploys the application to various environments

set -e

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

# Script directory and project root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../" && pwd)"

# Configuration
DEPLOY_ENV="production"
DEPLOY_DIR="$PROJECT_ROOT/deploy"
BACKUP_DIR="$PROJECT_ROOT/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")

# Function to print colored output
print_status() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function to check if a command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to check deployment requirements
check_deployment_requirements() {
    print_status "Checking deployment requirements..."

    local missing_deps=()

    # Check if deployment artifacts exist
    if [ ! -d "$DEPLOY_DIR" ]; then
        missing_deps+=("deployment_artifacts")
    fi

    if [ ! -f "$DEPLOY_DIR/manifest.json" ]; then
        missing_deps+=("deployment_manifest")
    fi

    # Check for deployment tools
    if [ "$DEPLOY_METHOD" = "docker" ]; then
        if ! command_exists docker; then
            missing_deps+=("docker")
        fi
    fi

    if [ "$DEPLOY_METHOD" = "rsync" ]; then
        if ! command_exists rsync; then
            missing_deps+=("rsync")
        fi
    fi

    if [ ${#missing_deps[@]} -ne 0 ]; then
        print_error "Missing deployment requirements: ${missing_deps[*]}"
        exit 1
    fi

    print_success "Deployment requirements met!"
}

# Function to create backup
create_backup() {
    print_status "Creating backup before deployment..."

    mkdir -p "$BACKUP_DIR"

    local backup_path="$BACKUP_DIR/backup_$TIMESTAMP"

    # Create backup directory
    mkdir -p "$backup_path"

    # Backup current deployment if it exists
    if [ -d "$DEPLOY_TARGET" ]; then
        print_status "Backing up current deployment..."
        cp -r "$DEPLOY_TARGET" "$backup_path/current"
    fi

    # Backup database if requested
    if [ "$BACKUP_DATABASE" = true ]; then
        print_status "Backing up database..."
        # This would depend on your database setup
        # For SQLite:
        if [ -f "$PROJECT_ROOT/backend/db.sqlite3" ]; then
            cp "$PROJECT_ROOT/backend/db.sqlite3" "$backup_path/database.sqlite3"
        fi
    fi

    # Backup environment files
    if [ -f "$PROJECT_ROOT/.env" ]; then
        cp "$PROJECT_ROOT/.env" "$backup_path/.env.backup"
    fi

    print_success "Backup created: $backup_path"
}

# Function to prepare deployment artifacts
prepare_artifacts() {
    print_status "Preparing deployment artifacts..."

    # Check if build artifacts exist
    if [ ! -d "$DEPLOY_DIR" ]; then
        print_error "No deployment artifacts found. Please run build-all.sh first."
        exit 1
    fi

    # Validate manifest
    if [ -f "$DEPLOY_DIR/manifest.json" ]; then
        print_status "Validating deployment manifest..."
        # You could add more validation here
        cat "$DEPLOY_DIR/manifest.json" | grep -q "build_timestamp" || {
            print_error "Invalid deployment manifest"
            exit 1
        }
    fi

    print_success "Deployment artifacts ready!"
}

# Function to deploy to local development
deploy_local() {
    print_status "Deploying to local development environment..."

    local target_dir="$PROJECT_ROOT/deployment"

    # Create target directory
    mkdir -p "$target_dir"

    # Copy artifacts
    print_status "Copying frontend artifacts..."
    cp -r "$DEPLOY_DIR/frontend" "$target_dir/"

    print_status "Copying backend artifacts..."
    mkdir -p "$target_dir/backend"
    cp -r "$DEPLOY_DIR/backend/staticfiles" "$target_dir/backend/"

    # Copy deployment configuration
    cp "$DEPLOY_DIR/manifest.json" "$target_dir/"

    print_success "Local deployment completed!"
    print_status "Deployment available at: $target_dir"
}

# Function to deploy via rsync
deploy_rsync() {
    print_status "Deploying via rsync..."

    if [ -z "$DEPLOY_HOST" ]; then
        print_error "DEPLOY_HOST not set for rsync deployment"
        exit 1
    fi

    local target=""

    if [ -n "$DEPLOY_USER" ]; then
        target="$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH"
    else
        target="$DEPLOY_HOST:$DEPLOY_PATH"
    fi

    print_status "Syncing files to $target..."

    # Rsync options:
    # -a: archive mode (recursive, preserves attributes)
    # -v: verbose
    # -z: compress during transfer
    # --delete: delete files not in source
    # --exclude: exclude certain files
    rsync -avz --delete \
        --exclude='.git' \
        --exclude='node_modules' \
        --exclude='__pycache__' \
        --exclude='*.log' \
        "$DEPLOY_DIR/" "$target"

    print_success "Rsync deployment completed!"
}

# Function to deploy via Docker
deploy_docker() {
    print_status "Deploying via Docker..."

    local image_name="thrillwiki-$DEPLOY_ENV"
    local container_name="thrillwiki-$DEPLOY_ENV"

    # Build Docker image
    print_status "Building Docker image: $image_name"
    docker build -t "$image_name" \
        --build-arg DEPLOY_ENV="$DEPLOY_ENV" \
        -f "$PROJECT_ROOT/Dockerfile" \
        "$PROJECT_ROOT"

    # Stop existing container
    if docker ps -q -f name="$container_name" | grep -q .; then
        print_status "Stopping existing container..."
        docker stop "$container_name"
    fi

    # Remove existing container
    if docker ps -a -q -f name="$container_name" | grep -q .; then
        print_status "Removing existing container..."
        docker rm "$container_name"
    fi

    # Run new container
    print_status "Starting new container..."
    docker run -d \
        --name "$container_name" \
        -p 8080:80 \
        -e DEPLOY_ENV="$DEPLOY_ENV" \
        "$image_name"

    print_success "Docker deployment completed!"
    print_status "Container: $container_name"
    print_status "URL: http://localhost:8080"
}

# Function to run post-deployment checks
run_post_deploy_checks() {
    print_status "Running post-deployment checks..."

    local health_url=""

    case $DEPLOY_METHOD in
        "local")
            health_url="http://localhost:8080/health"
            ;;
        "docker")
            health_url="http://localhost:8080/health"
            ;;
        "rsync")
            if [ -n "$DEPLOY_HOST" ]; then
                health_url="http://$DEPLOY_HOST/health"
            fi
            ;;
    esac

    if [ -n "$health_url" ]; then
        print_status "Checking health endpoint: $health_url"
        if curl -s -f "$health_url" > /dev/null 2>&1; then
            print_success "Health check passed!"
        else
            print_warning "Health check failed. Please verify deployment."
        fi
    fi

    print_success "Post-deployment checks completed!"
}

# Function to generate deployment report
generate_deployment_report() {
    print_status "Generating deployment report..."

    local report_file="$PROJECT_ROOT/deployment-report-$DEPLOY_ENV-$TIMESTAMP.txt"

    cat > "$report_file" << EOF
ThrillWiki Deployment Report
============================

Deployment Information:
- Deployment Date: $(date)
- Environment: $DEPLOY_ENV
- Method: $DEPLOY_METHOD
- Project Root: $PROJECT_ROOT

Deployment Details:
- Source Directory: $DEPLOY_DIR
- Target: $DEPLOY_TARGET
- Backup Created: $([ "$CREATE_BACKUP" = true ] && echo "Yes" || echo "No")

Build Information:
$(if [ -f "$DEPLOY_DIR/manifest.json" ]; then
    cat "$DEPLOY_DIR/manifest.json"
else
    echo "No manifest found"
fi)

System Information:
- Hostname: $(hostname)
- User: $(whoami)
- OS: $(uname -s) $(uname -r)

Deployment Status: SUCCESS

Post-Deployment:
- Health Check: $([ "$RUN_CHECKS" = true ] && echo "Run" || echo "Skipped")
- Backup Location: $([ "$CREATE_BACKUP" = true ] && echo "$BACKUP_DIR/backup_$TIMESTAMP" || echo "None")

EOF

    print_success "Deployment report generated: $report_file"
}

# Function to show usage
show_usage() {
    cat << EOF
Usage: $0 [ENVIRONMENT] [OPTIONS]

Deploy ThrillWiki to the specified environment.

Environments:
    dev         Development environment
    staging     Staging environment
    production  Production environment

Options:
    -h, --help          Show this help message
    -m, --method METHOD Deployment method (local, rsync, docker)
    --no-backup         Skip backup creation
    --no-checks         Skip post-deployment checks
    --no-report         Skip deployment report generation

Examples:
    $0 production           # Deploy to production using default method
    $0 staging --method docker  # Deploy to staging using Docker
    $0 dev --no-backup      # Deploy to dev without backup

Environment Variables:
    DEPLOY_METHOD           Deployment method (default: local)
    DEPLOY_HOST             Target host for rsync deployment
    DEPLOY_USER             SSH user for rsync deployment
    DEPLOY_PATH             Target path for rsync deployment
    CREATE_BACKUP           Create backup before deployment (default: true)
    BACKUP_DATABASE         Backup database (default: false)

EOF
}

# Parse command line arguments
DEPLOY_METHOD="local"
CREATE_BACKUP=true
RUN_CHECKS=true
SKIP_REPORT=false

# Get environment from first argument
if [ $# -gt 0 ]; then
    case $1 in
        dev|staging|production)
            DEPLOY_ENV="$1"
            shift
            ;;
        -h|--help)
            show_usage
            exit 0
            ;;
        *)
            print_error "Invalid environment: $1"
            show_usage
            exit 1
            ;;
    esac
fi

# Parse remaining arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -m|--method)
            DEPLOY_METHOD="$2"
            shift 2
            ;;
        --no-backup)
            CREATE_BACKUP=false
            shift
            ;;
        --no-checks)
            RUN_CHECKS=false
            shift
            ;;
        --no-report)
            SKIP_REPORT=true
            shift
            ;;
        *)
            print_error "Unknown option: $1"
            show_usage
            exit 1
            ;;
    esac
done

# Override from environment variables
if [ ! -z "$DEPLOY_METHOD_ENV" ]; then
    DEPLOY_METHOD=$DEPLOY_METHOD_ENV
fi

if [ "$CREATE_BACKUP_ENV" = "false" ]; then
    CREATE_BACKUP=false
fi

# Set deployment target based on method
case $DEPLOY_METHOD in
    "local")
        DEPLOY_TARGET="$PROJECT_ROOT/deployment"
        ;;
    "rsync")
        DEPLOY_TARGET="${DEPLOY_USER:-}$(if [ -n "$DEPLOY_USER" ]; then echo "@"; fi)${DEPLOY_HOST:-localhost}:${DEPLOY_PATH:-/var/www/thrillwiki}"
        ;;
    "docker")
        DEPLOY_TARGET="docker_container"
        ;;
    *)
        print_error "Unsupported deployment method: $DEPLOY_METHOD"
        exit 1
        ;;
esac

# Print banner
echo -e "${GREEN}"
echo "=========================================="
echo "    ThrillWiki Deployment"
echo "=========================================="
echo -e "${NC}"

print_status "Environment: $DEPLOY_ENV"
print_status "Method: $DEPLOY_METHOD"
print_status "Target: $DEPLOY_TARGET"
print_status "Create backup: $CREATE_BACKUP"

# Check deployment requirements
check_deployment_requirements

# Prepare deployment artifacts
prepare_artifacts

# Create backup if requested
if [ "$CREATE_BACKUP" = true ]; then
    create_backup
else
    print_warning "Skipping backup creation as requested"
fi

# Deploy based on method
case $DEPLOY_METHOD in
    "local")
        deploy_local
        ;;
    "rsync")
        deploy_rsync
        ;;
    "docker")
        deploy_docker
        ;;
    *)
        print_error "Unsupported deployment method: $DEPLOY_METHOD"
        exit 1
        ;;
esac

# Run post-deployment checks
if [ "$RUN_CHECKS" = true ]; then
    run_post_deploy_checks
else
    print_warning "Skipping post-deployment checks as requested"
fi

# Generate deployment report
if [ "$SKIP_REPORT" = false ]; then
    generate_deployment_report
else
    print_warning "Skipping deployment report generation as requested"
fi

print_success "Deployment completed successfully!"
echo ""
print_status "Environment: $DEPLOY_ENV"
print_status "Method: $DEPLOY_METHOD"
print_status "Target: $DEPLOY_TARGET"
echo ""
print_status "Deployment report: $PROJECT_ROOT/deployment-report-$DEPLOY_ENV-$TIMESTAMP.txt"