#!/bin/bash

#############################################################################
# Plesk Helper Functions
# Provides Plesk-specific utilities for domain, user, and resource discovery
#############################################################################

# Source common functions if not already loaded
if [ -z "$TOOLKIT_BASE_DIR" ]; then
    SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    [ -f "$SCRIPT_DIR/common-functions.sh" ] && source "$SCRIPT_DIR/common-functions.sh" || { echo "ERROR: common-functions.sh not found" >&2; return 1; }
fi

#############################################################################
# PLESK CLI HELPERS
#############################################################################

# Check if Plesk CLI is available
plesk_cli_available() {
    [ -x "/usr/local/psa/bin/plesk" ]
}

# Execute Plesk CLI command with error handling
plesk_exec() {
    if ! plesk_cli_available; then
        print_error "Plesk CLI not available"
        return 1
    fi
    /usr/local/psa/bin/plesk "$@" 2>/dev/null
}

#############################################################################
# DOMAIN DISCOVERY
#############################################################################

# Get list of all domains
# Returns: One domain per line
plesk_list_domains() {
    if plesk_cli_available; then
        plesk_exec bin domain --list 2>/dev/null
    else
        # Fallback: scan vhosts directory
        ls -1 /var/www/vhosts/ 2>/dev/null | \
            grep -v "^system$\|^chroot$\|^\.skel$\|^default$\|^fs$" | \
            grep -v "^\." || true
    fi
}

#############################################################################
# USER DISCOVERY
#############################################################################

# Get list of all Plesk users (clients)
# Returns: One username per line
plesk_list_users() {
    if plesk_cli_available; then
        # Try to get client logins from Plesk
        plesk_exec bin client --list 2>/dev/null | tail -n +3 | awk '{print $1}' | grep -v "^$"
    else
        # Fallback: Get unique owners from vhosts directories
        find /var/www/vhosts -maxdepth 1 -type d -printf "%f\n" 2>/dev/null | \
            grep -v "^system$\|^chroot$\|^\.skel$\|^default$\|^fs$\|^fs-passwd$" | \
            grep -v "^\." || true
    fi
}

# Get domain info
# Usage: plesk_domain_info DOMAIN
plesk_domain_info() {
    local domain="$1"
    [ -z "$domain" ] && return 1
    plesk_exec bin domain --info "$domain" 2>/dev/null
}

# Get domain document root
# Usage: plesk_get_docroot DOMAIN
# Returns: /var/www/vhosts/DOMAIN/httpdocs
plesk_get_docroot() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_domain_info "$domain" | grep -oP "www root:\s+\K.*" 2>/dev/null | head -1
    else
        # Fallback: standard path
        local docroot="/var/www/vhosts/$domain/httpdocs"
        [ -d "$docroot" ] && echo "$docroot"
    fi
}

# Get domain log directory
# Usage: plesk_get_logdir DOMAIN
# Returns: /var/www/vhosts/system/DOMAIN/logs (current) or /var/www/vhosts/DOMAIN/logs (future)
plesk_get_logdir() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    # Check new location first (Plesk 18.0.50+)
    if [ -d "/var/www/vhosts/$domain/logs" ]; then
        echo "/var/www/vhosts/$domain/logs"
        return 0
    fi

    # Check old location (Plesk 17.x - 18.0.49)
    if [ -d "/var/www/vhosts/system/$domain/logs" ]; then
        echo "/var/www/vhosts/system/$domain/logs"
        return 0
    fi

    return 1
}

# Get all domain log directories
# Returns: One log directory path per line for all domains
plesk_get_all_logdirs() {
    local logdirs=()

    # Try new location (Plesk 18.0.50+)
    while IFS= read -r dir; do
        [ -d "$dir" ] && logdirs+=("$dir")
    done < <(find /var/www/vhosts/*/logs -maxdepth 0 -type d 2>/dev/null | grep -v "/system/")

    # Try old location (Plesk 17.x - 18.0.49)
    while IFS= read -r dir; do
        [ -d "$dir" ] && logdirs+=("$dir")
    done < <(find /var/www/vhosts/system/*/logs -maxdepth 0 -type d 2>/dev/null)

    # Remove duplicates and print
    printf '%s\n' "${logdirs[@]}" | sort -u
}

# Get domain access log path
# Usage: plesk_get_access_log DOMAIN [ssl]
# Returns: Full path to access log
plesk_get_access_log() {
    local domain="$1"
    local ssl="${2:-}"
    local logdir

    logdir=$(plesk_get_logdir "$domain")
    [ -z "$logdir" ] && return 1

    if [ "$ssl" = "ssl" ]; then
        echo "$logdir/access_ssl_log"
    else
        echo "$logdir/access_log"
    fi
}

# Get domain error log path
# Usage: plesk_get_error_log DOMAIN
plesk_get_error_log() {
    local domain="$1"
    local logdir

    logdir=$(plesk_get_logdir "$domain")
    [ -z "$logdir" ] && return 1

    echo "$logdir/error_log"
}

#############################################################################
# USER/SUBSCRIPTION MANAGEMENT
#############################################################################

# Get list of all subscriptions
plesk_list_subscriptions() {
    if plesk_cli_available; then
        plesk_exec bin subscription --list 2>/dev/null
    else
        plesk_list_domains
    fi
}

# Get subscription owner for domain
# Usage: plesk_get_owner DOMAIN
plesk_get_owner() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_exec bin subscription --info "$domain" 2>/dev/null | \
            grep -oP "Owner's login:\s+\K.*" | head -1
    else
        # Fallback: check directory ownership
        stat -c "%U" "/var/www/vhosts/$domain" 2>/dev/null
    fi
}

#############################################################################
# DATABASE DISCOVERY
#############################################################################

# List all databases
plesk_list_databases() {
    if plesk_cli_available; then
        plesk_exec bin database --list 2>/dev/null
    else
        # Fallback: query MySQL directly
        mysql -e "SHOW DATABASES;" 2>/dev/null | grep -v "Database\|information_schema\|performance_schema\|mysql\|sys"
    fi
}

# List databases for specific domain
# Usage: plesk_list_domain_databases DOMAIN
plesk_list_domain_databases() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_exec bin database --list -domain "$domain" 2>/dev/null
    else
        # Fallback: guess based on naming convention (domain_dbname)
        local db_prefix=$(echo "$domain" | tr '.' '_' | tr '-' '_')
        plesk_list_databases | grep "^${db_prefix}_"
    fi
}

#############################################################################
# PHP VERSION DETECTION
#############################################################################

# List all available PHP handlers
plesk_list_php_handlers() {
    if plesk_cli_available; then
        plesk_exec bin php_handler --list 2>/dev/null
    else
        # Fallback: scan for PHP binaries
        find /opt/plesk/php/*/bin/php -type f -executable 2>/dev/null
    fi
}

# Get PHP version for domain
# Usage: plesk_get_domain_php DOMAIN
plesk_get_domain_php() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_exec bin site --info "$domain" 2>/dev/null | \
            grep -oP "PHP version:\s+\K.*" | head -1
    else
        # Fallback: check php-fpm socket config
        local php_ini="/var/www/vhosts/system/$domain/etc/php.ini"
        if [ -f "$php_ini" ]; then
            grep "^; configuration file" "$php_ini" | grep -oP '\d+\.\d+' | head -1
        fi
    fi
}

# Detect all Plesk-managed PHP versions
plesk_detect_php_versions() {
    local versions=()

    # Scan /opt/plesk/php/
    for php_bin in /opt/plesk/php/*/bin/php; do
        if [ -x "$php_bin" ]; then
            local version=$("$php_bin" -v 2>/dev/null | grep -oP '^PHP \K[\d.]+' | head -1)
            [ -n "$version" ] && versions+=("$version")
        fi
    done

    # Remove duplicates
    printf '%s\n' "${versions[@]}" | sort -u -V
}

#############################################################################
# PHP-FPM POOL DISCOVERY
#############################################################################

# Find all PHP-FPM pool sockets
plesk_list_fpm_sockets() {
    find /var/www/vhosts/system/*/php-fpm.sock -type s 2>/dev/null
}

# Get PHP-FPM socket for domain
# Usage: plesk_get_fpm_socket DOMAIN
plesk_get_fpm_socket() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    local socket="/var/www/vhosts/system/$domain/php-fpm.sock"
    [ -S "$socket" ] && echo "$socket"
}

#############################################################################
# CONFIGURATION FILE DISCOVERY
#############################################################################

# Get domain config directory
# Usage: plesk_get_confdir DOMAIN
plesk_get_confdir() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    local confdir="/var/www/vhosts/system/$domain/conf"
    [ -d "$confdir" ] && echo "$confdir"
}

# Get Apache vhost config
# Usage: plesk_get_httpd_conf DOMAIN
plesk_get_httpd_conf() {
    local domain="$1"
    local confdir

    confdir=$(plesk_get_confdir "$domain")
    [ -z "$confdir" ] && return 1

    echo "$confdir/httpd.conf"
}

# Get Nginx config
# Usage: plesk_get_nginx_conf DOMAIN
plesk_get_nginx_conf() {
    local domain="$1"
    local confdir

    confdir=$(plesk_get_confdir "$domain")
    [ -z "$confdir" ] && return 1

    echo "$confdir/nginx.conf"
}

# Get PHP config (php.ini)
# Usage: plesk_get_php_ini DOMAIN
plesk_get_php_ini() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    local php_ini="/var/www/vhosts/system/$domain/etc/php.ini"
    [ -f "$php_ini" ] && echo "$php_ini"
}

#############################################################################
# MAIL FUNCTIONS
#############################################################################

# Get mailbox directory for user@domain
# Usage: plesk_get_mailbox_dir DOMAIN USERNAME
plesk_get_mailbox_dir() {
    local domain="$1"
    local username="$2"
    [ -z "$domain" ] || [ -z "$username" ] && return 1

    local maildir="/var/qmail/mailnames/$domain/$username/Maildir"
    [ -d "$maildir" ] && echo "$maildir"
}

# List all mailboxes for domain
# Usage: plesk_list_mailboxes DOMAIN
plesk_list_mailboxes() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_exec bin mail --list "$domain" 2>/dev/null
    else
        # Fallback: scan mailnames directory
        [ -d "/var/qmail/mailnames/$domain" ] && \
            ls -1 "/var/qmail/mailnames/$domain/" 2>/dev/null
    fi
}

#############################################################################
# SERVICE MANAGEMENT
#############################################################################

# Restart Apache
plesk_restart_apache() {
    if plesk_cli_available; then
        plesk_exec bin service_node --restart httpd
    else
        systemctl restart httpd 2>/dev/null || service httpd restart 2>/dev/null
    fi
}

# Restart Nginx
plesk_restart_nginx() {
    if plesk_cli_available; then
        plesk_exec bin service_node --restart nginx
    else
        systemctl restart nginx 2>/dev/null || service nginx restart 2>/dev/null
    fi
}

# Restart PHP-FPM for all versions
plesk_restart_phpfpm() {
    if plesk_cli_available; then
        # Restart all Plesk PHP-FPM services
        for service in /etc/systemd/system/plesk-php*-fpm.service; do
            [ -f "$service" ] && systemctl restart "$(basename "$service")" 2>/dev/null
        done
    else
        systemctl restart php-fpm 2>/dev/null || service php-fpm restart 2>/dev/null
    fi
}

#############################################################################
# UTILITY FUNCTIONS
#############################################################################

# Check if domain exists in Plesk
# Usage: plesk_domain_exists DOMAIN
plesk_domain_exists() {
    local domain="$1"
    [ -z "$domain" ] && return 1

    if plesk_cli_available; then
        plesk_domain_info "$domain" > /dev/null 2>&1
        return $?
    else
        [ -d "/var/www/vhosts/$domain" ] || [ -d "/var/www/vhosts/system/$domain" ]
    fi
}

# Get Plesk version
plesk_get_version() {
    if [ -f "/usr/local/psa/version" ]; then
        head -1 /usr/local/psa/version
    else
        echo "unknown"
    fi
}

# Check if Plesk version is 18.0.50 or higher (new log location)
plesk_is_new_log_structure() {
    local version
    version=$(plesk_get_version)

    # Parse version (format: 18.0.50)
    local major minor patch
    major=$(echo "$version" | cut -d'.' -f1)
    minor=$(echo "$version" | cut -d'.' -f2)
    patch=$(echo "$version" | cut -d'.' -f3)

    # Check if >= 18.0.50
    if [ "$major" -gt 18 ]; then
        return 0
    elif [ "$major" -eq 18 ] && [ "$minor" -gt 0 ]; then
        return 0
    elif [ "$major" -eq 18 ] && [ "$minor" -eq 0 ] && [ "${patch:-0}" -ge 50 ]; then
        return 0
    fi

    return 1
}

# Get all domain names and document roots as TSV
# Format: DOMAIN\t/path/to/httpdocs
plesk_list_domains_with_docroots() {
    local domain docroot

    while IFS= read -r domain; do
        docroot=$(plesk_get_docroot "$domain")
        [ -n "$docroot" ] && echo -e "$domain\t$docroot"
    done < <(plesk_list_domains)
}

# Export all functions
export -f plesk_cli_available
export -f plesk_exec
export -f plesk_list_domains
export -f plesk_domain_info
export -f plesk_get_docroot
export -f plesk_get_logdir
export -f plesk_get_all_logdirs
export -f plesk_get_access_log
export -f plesk_get_error_log
export -f plesk_list_subscriptions
export -f plesk_get_owner
export -f plesk_list_databases
export -f plesk_list_domain_databases
export -f plesk_list_php_handlers
export -f plesk_get_domain_php
export -f plesk_detect_php_versions
export -f plesk_list_fpm_sockets
export -f plesk_get_fpm_socket
export -f plesk_get_confdir
export -f plesk_get_httpd_conf
export -f plesk_get_nginx_conf
export -f plesk_get_php_ini
export -f plesk_get_mailbox_dir
export -f plesk_list_mailboxes
export -f plesk_restart_apache
export -f plesk_restart_nginx
export -f plesk_restart_phpfpm
export -f plesk_domain_exists
export -f plesk_get_version
export -f plesk_is_new_log_structure
export -f plesk_list_domains_with_docroots
