#!/bin/bash

# Deploy Atoms - Atomic Functions Library
# Basic building blocks for deployment operations
#
# This file contains the smallest, reusable functions that form the foundation
# of the deployment system. Each function does ONE thing well.
#
# Usage:
#   source "$(dirname "$0")/_deploy-atoms.sh"

# ==============================================================================
# COLORS & FORMATTING
# ==============================================================================

export COLOR_GREEN='\033[0;32m'
export COLOR_YELLOW='\033[1;33m'
export COLOR_RED='\033[0;31m'
export COLOR_BLUE='\033[0;34m'
export COLOR_GRAY='\033[0;37m'
export COLOR_CYAN='\033[0;36m'
export COLOR_NC='\033[0m'  # No Color

# ==============================================================================
# LOGGING FUNCTIONS
# ==============================================================================

# Log info message
log_info() {
    echo -e "${COLOR_BLUE}ℹ${COLOR_NC}  $*"
}

# Log success message
log_success() {
    echo -e "${COLOR_GREEN}✓${COLOR_NC}  $*"
}

# Log warning message
log_warning() {
    echo -e "${COLOR_YELLOW}⚠${COLOR_NC}  $*"
}

# Log error message
log_error() {
    echo -e "${COLOR_RED}✗${COLOR_NC}  $*" >&2
}

# Log step header
log_step() {
    local step_num="$1"
    local total_steps="$2"
    local message="$3"
    echo ""
    echo -e "${COLOR_YELLOW}[${step_num}/${total_steps}]${COLOR_NC} ${COLOR_GREEN}${message}${COLOR_NC}"
}

# Log section header
log_section() {
    echo ""
    echo -e "${COLOR_CYAN}========================================${COLOR_NC}"
    echo -e "${COLOR_CYAN}  $*${COLOR_NC}"
    echo -e "${COLOR_CYAN}========================================${COLOR_NC}"
    echo ""
}

# ==============================================================================
# VALIDATION FUNCTIONS
# ==============================================================================

# Check if command exists
command_exists() {
    command -v "$1" &> /dev/null
}

# Check if file exists
file_exists() {
    [[ -f "$1" ]]
}

# Check if directory exists
dir_exists() {
    [[ -d "$1" ]]
}

# Check if string is empty
is_empty() {
    [[ -z "$1" ]]
}

# Check if string is not empty
is_not_empty() {
    [[ -n "$1" ]]
}

# Check if value is a number
is_number() {
    [[ "$1" =~ ^[0-9]+$ ]]
}

# Check if PHP version meets minimum requirement
check_php_version() {
    local required_version="$1"
    local current_version=$(php -r 'echo PHP_VERSION;' 2>/dev/null || echo "0")

    # Simple version comparison (works for major.minor)
    local required_major=$(echo "$required_version" | cut -d. -f1)
    local current_major=$(echo "$current_version" | cut -d. -f1)

    [[ "$current_major" -ge "$required_major" ]]
}

# ==============================================================================
# ENVIRONMENT DETECTION
# ==============================================================================

# Detect if running on cPanel server
is_cpanel_server() {
    [[ -d "/opt/cpanel" ]] || [[ -f "/usr/local/cpanel/version" ]]
}

# Detect if Supervisor is available
has_supervisor() {
    command_exists supervisorctl
}

# Detect if screen is available
has_screen() {
    command_exists screen
}

# Get PHP binary path
get_php_path() {
    # Check for cPanel PHP 8.1 first
    if [[ -f "/opt/cpanel/ea-php81/root/usr/bin/php" ]]; then
        echo "/opt/cpanel/ea-php81/root/usr/bin/php"
    else
        echo "php"
    fi
}

# Get PHP version string
get_php_version() {
    php -r 'echo PHP_VERSION;' 2>/dev/null || echo "unknown"
}

# Get Laravel version
get_laravel_version() {
    php artisan --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown"
}

# Get database type from .env
get_db_type() {
    if [[ -f ".env" ]]; then
        grep "^DB_CONNECTION=" .env | cut -d'=' -f2 | tr -d '"' | xargs || echo "mysql"
    else
        echo "mysql"
    fi
}

# Get database name from .env
get_db_name() {
    if [[ -f ".env" ]]; then
        grep "^DB_DATABASE=" .env | cut -d'=' -f2 | tr -d '"' | xargs || echo "unknown"
    else
        echo "unknown"
    fi
}

# Get database host from .env
get_db_host() {
    if [[ -f ".env" ]]; then
        grep "^DB_HOST=" .env | cut -d'=' -f2 | tr -d '"' | xargs || echo "localhost"
    else
        echo "localhost"
    fi
}

# Get database username from .env
get_db_user() {
    if [[ -f ".env" ]]; then
        grep "^DB_USERNAME=" .env | cut -d'=' -f2 | tr -d '"' | xargs
    fi
}

# Get database password from .env (as-is, may contain special chars)
get_db_password() {
    if [[ -f ".env" ]]; then
        grep "^DB_PASSWORD=" .env | cut -d'=' -f2-
    fi
}

# Check database connection via direct mysql CLI, bypassing Laravel bootstrap.
# This is more reliable than `artisan tinker` because it doesn't require the
# app's service providers / autoloader / config cache to be in a working state.
# Returns 0 on success, non-zero on failure. Stderr contains the mysql error.
check_database_connection() {
    local db_host db_user db_pass db_name
    db_host=$(get_db_host)
    db_user=$(get_db_user)
    db_pass=$(get_db_password)
    db_name=$(get_db_name)

    if [[ -z "$db_user" || -z "$db_name" ]]; then
        echo "DB credentials missing from .env" >&2
        return 1
    fi

    if ! command -v mysql &> /dev/null; then
        # Fall back to PHP PDO if mysql CLI isn't available
        php -r "
            try {
                \$pdo = new PDO('mysql:host=${db_host};dbname=${db_name}', '${db_user}', getenv('DEPLOY_DB_PASSWORD'));
                \$pdo->query('SELECT 1');
                exit(0);
            } catch (Exception \$e) {
                fwrite(STDERR, \$e->getMessage() . PHP_EOL);
                exit(1);
            }
        " 2>&1 DEPLOY_DB_PASSWORD="$db_pass"
        return $?
    fi

    MYSQL_PWD="$db_pass" mysql -u "$db_user" -h "$db_host" -N -B -e "SELECT 1" "$db_name" > /dev/null 2>&1
}

# Get app environment
get_app_env() {
    if [[ -f ".env" ]]; then
        grep "^APP_ENV=" .env | cut -d'=' -f2 | tr -d '"' | xargs || echo "production"
    else
        echo "production"
    fi
}

# Get current git branch
get_git_branch() {
    git branch --show-current 2>/dev/null || echo "unknown"
}

# Get current git commit hash
get_git_commit() {
    git rev-parse HEAD 2>/dev/null || echo "unknown"
}

# Get short git commit hash
get_git_commit_short() {
    git rev-parse --short HEAD 2>/dev/null || echo "unknown"
}

# ==============================================================================
# FILE OPERATIONS
# ==============================================================================

# Create directory if it doesn't exist
ensure_dir() {
    local dir="$1"
    if ! dir_exists "$dir"; then
        mkdir -p "$dir"
    fi
}

# Check if file is writable
is_writable() {
    [[ -w "$1" ]]
}

# Check if file is readable
is_readable() {
    [[ -r "$1" ]]
}

# Get file size in human-readable format
get_file_size() {
    du -h "$1" 2>/dev/null | cut -f1 || echo "0"
}

# ==============================================================================
# PROCESS MANAGEMENT
# ==============================================================================

# Check if queue worker is running
is_queue_worker_running() {
    pgrep -f "queue:work" > /dev/null
}

# Check if screen session exists
screen_session_exists() {
    local session_name="$1"
    screen -list | grep -q "$session_name"
}

# Get PID of queue worker
get_queue_worker_pid() {
    pgrep -f "queue:work" | head -1 || echo "0"
}

# ==============================================================================
# TIME OPERATIONS
# ==============================================================================

# Get current timestamp in ISO 8601 format
get_timestamp() {
    date -u +"%Y-%m-%dT%H:%M:%SZ"
}

# Get current timestamp for filenames
get_timestamp_filename() {
    date +"%Y%m%d_%H%M%S"
}

# Get current date for logs
get_date_log() {
    date +"%Y-%m-%d"
}

# ==============================================================================
# STRING OPERATIONS
# ==============================================================================

# Trim whitespace from string
trim() {
    echo "$1" | xargs
}

# Convert string to lowercase
to_lowercase() {
    echo "$1" | tr '[:upper:]' '[:lower:]'
}

# Convert string to uppercase
to_uppercase() {
    echo "$1" | tr '[:lower:]' '[:upper:]'
}

# ==============================================================================
# ERROR HANDLING
# ==============================================================================

# Exit with error message
die() {
    log_error "$*"
    exit 1
}

# Assert condition is true
assert() {
    if ! "$@"; then
        die "Assertion failed: $*"
    fi
}

# Require command to exist
require_command() {
    if ! command_exists "$1"; then
        die "Required command not found: $1"
    fi
}

# Require file to exist
require_file() {
    if ! file_exists "$1"; then
        die "Required file not found: $1"
    fi
}

# Require directory to exist
require_dir() {
    if ! dir_exists "$1"; then
        die "Required directory not found: $1"
    fi
}

# ==============================================================================
# CONFIGURATION
# ==============================================================================

# Read value from .env file
read_env() {
    local key="$1"
    local default="${2:-}"

    if [[ -f ".env" ]]; then
        local value=$(grep "^${key}=" .env | cut -d'=' -f2- | tr -d '"' | xargs)
        echo "${value:-$default}"
    else
        echo "$default"
    fi
}

# Check if .env key exists and is not empty
env_key_exists() {
    local key="$1"
    local value=$(read_env "$key")
    is_not_empty "$value"
}

# ==============================================================================
# EXPORT FUNCTIONS
# ==============================================================================

# Export all functions for use in other scripts
export -f log_info log_success log_warning log_error log_step log_section
export -f command_exists file_exists dir_exists is_empty is_not_empty is_number
export -f check_php_version
export -f is_cpanel_server has_supervisor has_screen
export -f get_php_path get_php_version get_laravel_version
export -f get_db_type get_db_name get_db_host get_db_user get_db_password get_app_env
export -f check_database_connection
export -f get_git_branch get_git_commit get_git_commit_short
export -f ensure_dir is_writable is_readable get_file_size
export -f is_queue_worker_running screen_session_exists get_queue_worker_pid
export -f get_timestamp get_timestamp_filename get_date_log
export -f trim to_lowercase to_uppercase
export -f die assert require_command require_file require_dir
export -f read_env env_key_exists
