#!/bin/bash

# TankStopp Docker Deployment Script
# This script deploys the TankStopp application using Docker Compose

set -e  # Exit on any error

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

# Default values
ENVIRONMENT="production"
ACTION="deploy"
SERVICE_NAME="tankstopp"
COMPOSE_FILE="docker-compose.yml"
COMPOSE_OVERRIDE=""
PROJECT_NAME="tankstopp"
BACKUP_BEFORE_DEPLOY=true
WAIT_TIMEOUT=300
HEALTH_CHECK_RETRIES=10
ROLLBACK_ON_FAILURE=true
SCALE_REPLICAS=1

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DATA_DIR="/var/lib/tankstopp"
BACKUP_DIR="/var/lib/tankstopp/backups"
LOG_DIR="/var/log/tankstopp"

# Functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_debug() {
    if [ "$DEBUG" = true ]; then
        echo -e "${PURPLE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
    fi
}

show_help() {
    cat << EOF
TankStopp Docker Deployment Script

Usage: $0 [ACTION] [OPTIONS]

ACTIONS:
    deploy              Deploy the application (default)
    start               Start existing containers
    stop                Stop running containers
    restart             Restart containers
    update              Update to latest images
    rollback            Rollback to previous version
    status              Show deployment status
    logs                Show application logs
    backup              Create database backup
    restore             Restore from backup
    scale               Scale service replicas
    cleanup             Clean up unused resources

OPTIONS:
    -h, --help                    Show this help message
    -e, --env ENV                 Environment: development|production|staging (default: production)
    -f, --file FILE               Docker compose file (default: docker-compose.yml)
    -o, --override FILE           Docker compose override file
    -p, --project NAME            Project name (default: tankstopp)
    -s, --service NAME            Service name (default: tankstopp)
    -r, --replicas COUNT          Number of replicas for scaling (default: 1)
    -t, --timeout SECONDS         Wait timeout in seconds (default: 300)
    --no-backup                   Skip backup before deployment
    --no-rollback                 Don't rollback on failure
    --force                       Force action without confirmation
    --debug                       Enable debug logging

EXAMPLES:
    # Deploy to production
    $0 deploy --env production

    # Deploy with custom compose file
    $0 deploy --file docker-compose.prod.yml

    # Start development environment
    $0 start --env development

    # Scale production service
    $0 scale --replicas 3

    # View logs
    $0 logs --service tankstopp

    # Backup database
    $0 backup

    # Rollback deployment
    $0 rollback

ENVIRONMENT CONFIGURATIONS:
    development     - Local development with debug enabled
    staging         - Staging environment for testing
    production      - Production deployment with optimizations

EOF
}

check_requirements() {
    log_info "Checking deployment requirements..."

    # Check Docker
    if ! command -v docker &> /dev/null; then
        log_error "Docker is not installed or not in PATH"
        exit 1
    fi

    # Check Docker Compose
    if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
        log_error "Docker Compose is not installed or not in PATH"
        exit 1
    fi

    # Set Docker Compose command
    if docker compose version &> /dev/null; then
        DOCKER_COMPOSE_CMD="docker compose"
    else
        DOCKER_COMPOSE_CMD="docker-compose"
    fi

    # Check Docker daemon
    if ! docker info &> /dev/null; then
        log_error "Docker daemon is not running"
        exit 1
    fi

    # Check compose file
    if [ ! -f "$PROJECT_ROOT/$COMPOSE_FILE" ]; then
        log_error "Docker Compose file not found: $PROJECT_ROOT/$COMPOSE_FILE"
        exit 1
    fi

    log_success "Requirements check passed"
}

setup_environment() {
    log_info "Setting up environment: $ENVIRONMENT"

    # Create necessary directories
    create_directories

    # Set compose files based on environment
    case "$ENVIRONMENT" in
        "development")
            COMPOSE_OVERRIDE="docker-compose.override.yml"
            ;;
        "staging")
            COMPOSE_OVERRIDE="docker-compose.staging.yml"
            ;;
        "production")
            COMPOSE_OVERRIDE="docker-compose.prod.yml"
            ;;
    esac

    # Build compose command
    COMPOSE_CMD="$DOCKER_COMPOSE_CMD -p $PROJECT_NAME -f $COMPOSE_FILE"
    if [ -n "$COMPOSE_OVERRIDE" ] && [ -f "$PROJECT_ROOT/$COMPOSE_OVERRIDE" ]; then
        COMPOSE_CMD="$COMPOSE_CMD -f $COMPOSE_OVERRIDE"
        log_info "Using override file: $COMPOSE_OVERRIDE"
    fi

    log_success "Environment setup completed"
}

create_directories() {
    log_info "Creating necessary directories..."

    # Create directories with proper permissions
    sudo mkdir -p "$DATA_DIR/data" "$BACKUP_DIR" "$LOG_DIR"
    sudo chown -R 1001:1001 "$DATA_DIR" 2>/dev/null || true
    sudo chmod -R 755 "$DATA_DIR" 2>/dev/null || true

    log_success "Directories created"
}

backup_database() {
    if [ "$BACKUP_BEFORE_DEPLOY" = false ]; then
        log_info "Skipping backup (disabled)"
        return 0
    fi

    log_info "Creating database backup..."

    local backup_file="$BACKUP_DIR/fuel_stops_$(date +%Y%m%d_%H%M%S).db"

    # Check if database exists
    if [ ! -f "$DATA_DIR/data/fuel_stops.db" ]; then
        log_warning "Database file not found, skipping backup"
        return 0
    fi

    # Create backup
    if cp "$DATA_DIR/data/fuel_stops.db" "$backup_file"; then
        log_success "Database backup created: $backup_file"

        # Keep only last 10 backups
        find "$BACKUP_DIR" -name "fuel_stops_*.db" -type f | sort -r | tail -n +11 | xargs rm -f 2>/dev/null || true
    else
        log_error "Failed to create database backup"
        return 1
    fi
}

pull_images() {
    log_info "Pulling latest images..."

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD pull; then
        log_success "Images pulled successfully"
    else
        log_error "Failed to pull images"
        return 1
    fi
}

deploy_application() {
    log_info "Deploying TankStopp application..."

    cd "$PROJECT_ROOT"

    # Backup database
    backup_database

    # Pull latest images
    pull_images

    # Deploy with docker-compose
    log_info "Starting containers..."
    if $COMPOSE_CMD up -d --remove-orphans; then
        log_success "Containers started successfully"
    else
        log_error "Failed to start containers"
        if [ "$ROLLBACK_ON_FAILURE" = true ]; then
            log_info "Attempting rollback..."
            rollback_deployment
        fi
        return 1
    fi

    # Wait for services to be healthy
    wait_for_health

    # Run post-deployment checks
    post_deployment_checks

    log_success "Application deployed successfully"
}

wait_for_health() {
    log_info "Waiting for services to become healthy..."

    local retries=0
    local max_retries=$HEALTH_CHECK_RETRIES

    while [ $retries -lt $max_retries ]; do
        if check_service_health; then
            log_success "All services are healthy"
            return 0
        fi

        retries=$((retries + 1))
        log_info "Health check attempt $retries/$max_retries..."
        sleep 10
    done

    log_error "Services failed to become healthy within timeout"
    return 1
}

check_service_health() {
    cd "$PROJECT_ROOT"

    # Check container status
    local unhealthy_containers=$($COMPOSE_CMD ps --filter "status=unhealthy" --format "{{.Service}}" 2>/dev/null | wc -l)
    local running_containers=$($COMPOSE_CMD ps --filter "status=running" --format "{{.Service}}" 2>/dev/null | wc -l)

    log_debug "Running containers: $running_containers, Unhealthy containers: $unhealthy_containers"

    if [ "$unhealthy_containers" -gt 0 ]; then
        log_warning "Found $unhealthy_containers unhealthy containers"
        return 1
    fi

    if [ "$running_containers" -eq 0 ]; then
        log_warning "No running containers found"
        return 1
    fi

    # Test HTTP endpoint
    if command -v curl &> /dev/null; then
        local port=$(get_service_port)
        if curl -sf "http://localhost:$port/" > /dev/null 2>&1; then
            return 0
        else
            log_debug "HTTP health check failed"
            return 1
        fi
    fi

    return 0
}

get_service_port() {
    case "$ENVIRONMENT" in
        "development")
            echo "8081"
            ;;
        *)
            echo "8080"
            ;;
    esac
}

post_deployment_checks() {
    log_info "Running post-deployment checks..."

    cd "$PROJECT_ROOT"

    # Check container logs for errors
    local error_count=$($COMPOSE_CMD logs --tail=50 "$SERVICE_NAME" 2>/dev/null | grep -i "error\|panic\|fatal" | wc -l)
    if [ "$error_count" -gt 0 ]; then
        log_warning "Found $error_count error messages in logs"
        log_info "Recent errors:"
        $COMPOSE_CMD logs --tail=10 "$SERVICE_NAME" | grep -i "error\|panic\|fatal" || true
    fi

    # Check resource usage
    check_resource_usage

    log_success "Post-deployment checks completed"
}

check_resource_usage() {
    log_info "Checking resource usage..."

    cd "$PROJECT_ROOT"

    # Get container stats
    local stats=$($COMPOSE_CMD exec -T "$SERVICE_NAME" sh -c "
        echo 'Memory usage:'
        free -h | grep Mem
        echo 'Disk usage:'
        df -h /app/data
        echo 'CPU info:'
        uptime
    " 2>/dev/null || echo "Could not retrieve stats")

    log_debug "Resource stats: $stats"
}

start_services() {
    log_info "Starting services..."

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD start; then
        log_success "Services started successfully"
        wait_for_health
    else
        log_error "Failed to start services"
        return 1
    fi
}

stop_services() {
    log_info "Stopping services..."

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD stop; then
        log_success "Services stopped successfully"
    else
        log_error "Failed to stop services"
        return 1
    fi
}

restart_services() {
    log_info "Restarting services..."

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD restart; then
        log_success "Services restarted successfully"
        wait_for_health
    else
        log_error "Failed to restart services"
        return 1
    fi
}

update_application() {
    log_info "Updating application..."

    backup_database
    pull_images

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD up -d --remove-orphans; then
        log_success "Application updated successfully"
        wait_for_health
        post_deployment_checks
    else
        log_error "Failed to update application"
        return 1
    fi
}

rollback_deployment() {
    log_info "Rolling back deployment..."

    cd "$PROJECT_ROOT"

    # Stop current containers
    $COMPOSE_CMD down

    # Restore from latest backup
    local latest_backup=$(find "$BACKUP_DIR" -name "fuel_stops_*.db" -type f | sort -r | head -n 1)
    if [ -n "$latest_backup" ] && [ -f "$latest_backup" ]; then
        log_info "Restoring database from: $latest_backup"
        cp "$latest_backup" "$DATA_DIR/data/fuel_stops.db"
        log_success "Database restored"
    else
        log_warning "No backup found for rollback"
    fi

    # Start with previous configuration
    if $COMPOSE_CMD up -d; then
        log_success "Rollback completed successfully"
    else
        log_error "Rollback failed"
        return 1
    fi
}

show_status() {
    log_info "Deployment status:"

    cd "$PROJECT_ROOT"

    echo ""
    echo "=== Container Status ==="
    $COMPOSE_CMD ps

    echo ""
    echo "=== Service Health ==="
    if check_service_health; then
        echo -e "${GREEN}✓ Services are healthy${NC}"
    else
        echo -e "${RED}✗ Services are unhealthy${NC}"
    fi

    echo ""
    echo "=== Resource Usage ==="
    check_resource_usage

    echo ""
    echo "=== Recent Logs ==="
    $COMPOSE_CMD logs --tail=5 "$SERVICE_NAME"
}

show_logs() {
    log_info "Showing application logs..."

    cd "$PROJECT_ROOT"
    $COMPOSE_CMD logs -f "$SERVICE_NAME"
}

scale_service() {
    log_info "Scaling service to $SCALE_REPLICAS replicas..."

    cd "$PROJECT_ROOT"
    if $COMPOSE_CMD up -d --scale "$SERVICE_NAME=$SCALE_REPLICAS"; then
        log_success "Service scaled to $SCALE_REPLICAS replicas"
        wait_for_health
    else
        log_error "Failed to scale service"
        return 1
    fi
}

cleanup_resources() {
    log_info "Cleaning up unused resources..."

    # Remove unused containers
    docker container prune -f

    # Remove unused images
    docker image prune -f

    # Remove unused volumes (be careful!)
    if [ "$FORCE" = true ]; then
        docker volume prune -f
    fi

    # Remove unused networks
    docker network prune -f

    log_success "Cleanup completed"
}

restore_backup() {
    log_info "Available backups:"
    ls -la "$BACKUP_DIR"/fuel_stops_*.db 2>/dev/null || {
        log_error "No backups found in $BACKUP_DIR"
        return 1
    }

    echo ""
    read -p "Enter backup filename to restore (or 'latest' for most recent): " backup_choice

    local backup_file
    if [ "$backup_choice" = "latest" ]; then
        backup_file=$(find "$BACKUP_DIR" -name "fuel_stops_*.db" -type f | sort -r | head -n 1)
    else
        backup_file="$BACKUP_DIR/$backup_choice"
    fi

    if [ ! -f "$backup_file" ]; then
        log_error "Backup file not found: $backup_file"
        return 1
    fi

    log_info "Restoring from: $backup_file"

    # Stop services
    stop_services

    # Restore database
    cp "$backup_file" "$DATA_DIR/data/fuel_stops.db"

    # Start services
    start_services

    log_success "Database restored successfully"
}

main() {
    # Parse command line arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            deploy|start|stop|restart|update|rollback|status|logs|backup|restore|scale|cleanup)
                ACTION="$1"
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            -e|--env)
                ENVIRONMENT="$2"
                shift 2
                ;;
            -f|--file)
                COMPOSE_FILE="$2"
                shift 2
                ;;
            -o|--override)
                COMPOSE_OVERRIDE="$2"
                shift 2
                ;;
            -p|--project)
                PROJECT_NAME="$2"
                shift 2
                ;;
            -s|--service)
                SERVICE_NAME="$2"
                shift 2
                ;;
            -r|--replicas)
                SCALE_REPLICAS="$2"
                shift 2
                ;;
            -t|--timeout)
                WAIT_TIMEOUT="$2"
                shift 2
                ;;
            --no-backup)
                BACKUP_BEFORE_DEPLOY=false
                shift
                ;;
            --no-rollback)
                ROLLBACK_ON_FAILURE=false
                shift
                ;;
            --force)
                FORCE=true
                shift
                ;;
            --debug)
                DEBUG=true
                shift
                ;;
            *)
                log_error "Unknown option: $1"
                show_help
                exit 1
                ;;
        esac
    done

    # Validate environment
    if [[ "$ENVIRONMENT" != "development" && "$ENVIRONMENT" != "staging" && "$ENVIRONMENT" != "production" ]]; then
        log_error "Invalid environment: $ENVIRONMENT"
        exit 1
    fi

    # Start deployment process
    log_info "Starting TankStopp deployment process..."
    log_info "Action: $ACTION"
    log_info "Environment: $ENVIRONMENT"
    log_info "Project: $PROJECT_NAME"

    check_requirements
    setup_environment

    # Execute action
    case "$ACTION" in
        "deploy")
            deploy_application
            ;;
        "start")
            start_services
            ;;
        "stop")
            stop_services
            ;;
        "restart")
            restart_services
            ;;
        "update")
            update_application
            ;;
        "rollback")
            rollback_deployment
            ;;
        "status")
            show_status
            ;;
        "logs")
            show_logs
            ;;
        "backup")
            backup_database
            ;;
        "restore")
            restore_backup
            ;;
        "scale")
            scale_service
            ;;
        "cleanup")
            cleanup_resources
            ;;
        *)
            log_error "Unknown action: $ACTION"
            show_help
            exit 1
            ;;
    esac

    log_success "Deployment process completed successfully!"
}

# Execute main function
main "$@"
