<?php

declare(strict_types=1);

/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 * 
 * Desk-Moloni v3.0 Bootstrap Configuration
 * 
 * Initializes the module environment, sets up autoloading,
 * and prepares the system for CLI and web operations.
 */

// Define module constants
if (!defined('DESK_MOLONI_VERSION')) {
    define('DESK_MOLONI_VERSION', '3.0.1');
}

if (!defined('DESK_MOLONI_MODULE_DIR')) {
    define('DESK_MOLONI_MODULE_DIR', dirname(__DIR__));
}

if (!defined('DESK_MOLONI_PROJECT_ROOT')) {
    define('DESK_MOLONI_PROJECT_ROOT', dirname(dirname(dirname(__DIR__))));
}

// Environment detection
$cli_mode = (php_sapi_name() === 'cli');
$debug_mode = isset($_ENV['DESK_MOLONI_DEBUG']) ? (bool)$_ENV['DESK_MOLONI_DEBUG'] : false;

// Set error reporting based on environment
if ($debug_mode) {
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    ini_set('log_errors', '1');
} else {
    error_reporting(E_ERROR | E_WARNING | E_PARSE);
    ini_set('display_errors', '0');
    ini_set('log_errors', '1');
}

// Set timezone
if (!ini_get('date.timezone')) {
    date_default_timezone_set('UTC');
}

// Set memory limit for CLI operations
if ($cli_mode) {
    ini_set('memory_limit', '256M');
    set_time_limit(0);
}

/**
 * Simple autoloader for Desk-Moloni classes
 */
spl_autoload_register(function ($className) {
    // Only handle DeskMoloni namespace
    if (strpos($className, 'DeskMoloni\\') !== 0) {
        return false;
    }
    
    // Convert namespace to file path
    $relativePath = str_replace('DeskMoloni\\', '', $className);
    $relativePath = str_replace('\\', DIRECTORY_SEPARATOR, $relativePath);
    
    // Common locations to check
    $possiblePaths = [
        DESK_MOLONI_MODULE_DIR . '/src/' . $relativePath . '.php',
        DESK_MOLONI_MODULE_DIR . '/lib/' . $relativePath . '.php',
        DESK_MOLONI_MODULE_DIR . '/classes/' . $relativePath . '.php'
    ];
    
    foreach ($possiblePaths as $path) {
        if (file_exists($path)) {
            require_once $path;
            return true;
        }
    }
    
    return false;
});

/**
 * Load Perfex CRM environment if available
 */
function loadPerfexEnvironment(): bool
{
    $perfexPaths = [
        DESK_MOLONI_PROJECT_ROOT . '/application/config/config.php',
        DESK_MOLONI_PROJECT_ROOT . '/config/config.php',
        dirname(DESK_MOLONI_PROJECT_ROOT) . '/application/config/config.php'
    ];
    
    foreach ($perfexPaths as $configPath) {
        if (file_exists($configPath)) {
            // Set up basic Perfex environment
            if (!defined('BASEPATH')) {
                define('BASEPATH', dirname($configPath) . '/');
            }
            
            if (!defined('APPPATH')) {
                define('APPPATH', dirname($configPath) . '/application/');
            }
            
            return true;
        }
    }
    
    return false;
}

/**
 * Initialize database connection
 */
function initializeDatabase(): ?PDO
{
    try {
        $configFile = DESK_MOLONI_MODULE_DIR . '/config/config.php';
        
        if (!file_exists($configFile)) {
            return null;
        }
        
        $config = include $configFile;
        
        if (!isset($config['database'])) {
            return null;
        }
        
        $dbConfig = $config['database'];
        
        // Try to get password from Perfex config if not provided
        $password = $dbConfig['password'] ?? '';
        if (empty($password) && loadPerfexEnvironment()) {
            // In a real implementation, this would extract the password from Perfex config
            $password = ''; // Placeholder
        }
        
        $dsn = sprintf(
            'mysql:host=%s;dbname=%s;charset=utf8mb4',
            $dbConfig['host'],
            $dbConfig['database']
        );
        
        $options = [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
        ];
        
        return new PDO($dsn, $dbConfig['username'], $password, $options);
        
    } catch (Exception $e) {
        if ($debug_mode) {
            error_log("Database connection failed: " . $e->getMessage());
        }
        return null;
    }
}

/**
 * Load configuration
 */
function loadConfiguration(): array
{
    $config = [];
    
    // Load main config
    $mainConfigFile = DESK_MOLONI_MODULE_DIR . '/config/config.php';
    if (file_exists($mainConfigFile)) {
        $config = include $mainConfigFile;
    }
    
    // Load environment-specific config
    $environment = $config['environment'] ?? 'production';
    $envConfigFile = DESK_MOLONI_MODULE_DIR . "/config/config.{$environment}.php";
    if (file_exists($envConfigFile)) {
        $envConfig = include $envConfigFile;
        $config = array_merge_recursive($config, $envConfig);
    }
    
    // Apply environment variables
    foreach ($_ENV as $key => $value) {
        if (strpos($key, 'DESK_MOLONI_') === 0) {
            $configKey = strtolower(str_replace('DESK_MOLONI_', '', $key));
            $config[$configKey] = $value;
        }
    }
    
    return $config;
}

/**
 * Initialize logging
 */
function initializeLogging(array $config): void
{
    $logDir = DESK_MOLONI_MODULE_DIR . '/logs';
    
    if (!is_dir($logDir)) {
        mkdir($logDir, 0755, true);
    }
    
    // Set error log path
    $errorLogPath = $logDir . '/error.log';
    ini_set('error_log', $errorLogPath);
    
    // Set up custom log handler if needed
    if (isset($config['logging']['level'])) {
        // Custom logging setup would go here
    }
}

/**
 * Initialize CLI environment
 */
function initializeCLI(): void
{
    if (!function_exists('readline')) {
        // Provide basic readline functionality if not available
        function readline($prompt = '') {
            echo $prompt;
            return trim(fgets(STDIN));
        }
    }
    
    // Set up signal handlers if available
    if (function_exists('pcntl_signal')) {
        // SIGTERM handler
        pcntl_signal(SIGTERM, function($signo) {
            echo "\nReceived SIGTERM, shutting down gracefully...\n";
            exit(0);
        });
        
        // SIGINT handler (Ctrl+C)
        pcntl_signal(SIGINT, function($signo) {
            echo "\nReceived SIGINT, shutting down gracefully...\n";
            exit(0);
        });
    }
}

/**
 * Global exception handler
 */
function handleUncaughtException(Throwable $exception): void
{
    $message = sprintf(
        "[%s] Uncaught %s: %s in %s:%d\nStack trace:\n%s",
        date('Y-m-d H:i:s'),
        get_class($exception),
        $exception->getMessage(),
        $exception->getFile(),
        $exception->getLine(),
        $exception->getTraceAsString()
    );
    
    error_log($message);
    
    if (php_sapi_name() === 'cli') {
        fprintf(STDERR, "Fatal error: %s\n", $exception->getMessage());
    }
}

/**
 * Global error handler
 */
function handleError(int $errno, string $errstr, string $errfile, int $errline): bool
{
    // Don't handle errors if error_reporting is 0 (@ operator used)
    if (error_reporting() === 0) {
        return false;
    }
    
    $errorTypes = [
        E_ERROR => 'ERROR',
        E_WARNING => 'WARNING',
        E_PARSE => 'PARSE',
        E_NOTICE => 'NOTICE',
        E_CORE_ERROR => 'CORE_ERROR',
        E_CORE_WARNING => 'CORE_WARNING',
        E_COMPILE_ERROR => 'COMPILE_ERROR',
        E_COMPILE_WARNING => 'COMPILE_WARNING',
        E_USER_ERROR => 'USER_ERROR',
        E_USER_WARNING => 'USER_WARNING',
        E_USER_NOTICE => 'USER_NOTICE',
        E_STRICT => 'STRICT',
        E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
        E_DEPRECATED => 'DEPRECATED',
        E_USER_DEPRECATED => 'USER_DEPRECATED'
    ];
    
    $errorType = $errorTypes[$errno] ?? 'UNKNOWN';
    
    $message = sprintf(
        "[%s] %s: %s in %s:%d",
        date('Y-m-d H:i:s'),
        $errorType,
        $errstr,
        $errfile,
        $errline
    );
    
    error_log($message);
    
    // Don't execute PHP internal error handler
    return true;
}

// Bootstrap initialization
try {
    // Load configuration
    $config = loadConfiguration();
    
    // Initialize logging
    initializeLogging($config);
    
    // Set exception and error handlers
    set_exception_handler('handleUncaughtException');
    set_error_handler('handleError');
    
    // Initialize CLI if in CLI mode
    if ($cli_mode) {
        initializeCLI();
    }
    
    // Try to load Perfex environment
    loadPerfexEnvironment();
    
    // Initialize database connection (lazy loading)
    $GLOBALS['desk_moloni_db'] = null;
    
    // Store configuration globally
    $GLOBALS['desk_moloni_config'] = $config;
    
} catch (Throwable $e) {
    error_log("Bootstrap failed: " . $e->getMessage());
    
    if ($cli_mode) {
        fprintf(STDERR, "Fatal error during bootstrap: %s\n", $e->getMessage());
        exit(1);
    } else {
        // In web mode, try to fail gracefully
        http_response_code(500);
        if ($debug_mode) {
            echo "Bootstrap error: " . $e->getMessage();
        } else {
            echo "Internal server error";
        }
        exit(1);
    }
}

/**
 * Utility functions
 */

/**
 * Get database connection (lazy initialization)
 */
function getDeskMoloniDB(): ?PDO
{
    if ($GLOBALS['desk_moloni_db'] === null) {
        $GLOBALS['desk_moloni_db'] = initializeDatabase();
    }
    
    return $GLOBALS['desk_moloni_db'];
}

/**
 * Get configuration value
 */
function getDeskMoloniConfig(string $key = null, $default = null)
{
    $config = $GLOBALS['desk_moloni_config'] ?? [];
    
    if ($key === null) {
        return $config;
    }
    
    // Support dot notation for nested keys
    $keys = explode('.', $key);
    $value = $config;
    
    foreach ($keys as $k) {
        if (!is_array($value) || !isset($value[$k])) {
            return $default;
        }
        $value = $value[$k];
    }
    
    return $value;
}

/**
 * Log message to application log
 */
function deskMoloniLog(string $level, string $message, array $context = []): void
{
    $logFile = DESK_MOLONI_MODULE_DIR . '/logs/application.log';
    
    $contextString = '';
    if (!empty($context)) {
        $contextString = ' ' . json_encode($context, JSON_UNESCAPED_SLASHES);
    }
    
    $logEntry = sprintf(
        "[%s] [%s] %s%s\n",
        date('Y-m-d H:i:s'),
        strtoupper($level),
        $message,
        $contextString
    );
    
    file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
}

/**
 * Check if running in CLI mode
 */
function isDeskMoloniCLI(): bool
{
    return php_sapi_name() === 'cli';
}

/**
 * Check if debug mode is enabled
 */
function isDeskMoloniDebug(): bool
{
    return getDeskMoloniConfig('debug', false) || 
           (isset($_ENV['DESK_MOLONI_DEBUG']) && $_ENV['DESK_MOLONI_DEBUG']);
}

/**
 * Get module version
 */
function getDeskMoloniVersion(): string
{
    $versionFile = DESK_MOLONI_MODULE_DIR . '/VERSION';

    if (file_exists($versionFile)) {
        return trim(file_get_contents($versionFile));
    }

    return DESK_MOLONI_VERSION;
}

/**
 * HTML escaping function for XSS protection
 * Converts special characters to HTML entities
 */
if (!function_exists('h')) {
    function h(?string $string, int $flags = ENT_QUOTES | ENT_HTML5, string $encoding = 'UTF-8', bool $double_encode = true): string
    {
        if ($string === null) {
            return '';
        }

        return htmlspecialchars($string, $flags, $encoding, $double_encode);
    }
}