<?php

namespace App\Core;

/**
 * Bootstrap — Application Initialization
 *
 * Performs the startup sequence in the exact order defined by
 * the Sprint 0 Execution Plan:
 *
 *   1. Load .env file into $_ENV
 *   2. Load helper functions (env, config, csrf_field)
 *   3. Register class autoloader
 *   4. Configure PHP error reporting
 *   5. Register error / exception handlers
 *   6. Set default timezone
 *   7. Start session with configured security settings (INIT-010)
 *
 * Step deferred to Application::handleRequest():
 *   - Request dispatch → Router::dispatch() (INIT-007)
 *
 * @package Inveetaire
 * @ref     DBP v1.0 Ch.5, Ch.6, SAD v1.1 Ch.4, INIT-003, INIT-010
 */
class Bootstrap
{
    /**
     * Execute the full initialization sequence.
     * Called once by Application::run().
     *
     * @return void
     */
    public function init(): void
    {
        $this->loadEnvironment();
        $this->loadHelpers();
        $this->configureErrorReporting();
        $this->registerErrorHandlers();
        $this->setTimezone();
        $this->startSession();         // INIT-010 — session must start before any
                                       // request processing, CSRF validation, or
                                       // flash message access.
        // Router::dispatch() → called by Application::handleRequest() (INIT-007)
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STEP 1 — ENVIRONMENT
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Parse the .env file and populate $_ENV with raw string values.
     *
     * Rules:
     *   - Lines beginning with # are comments — skipped.
     *   - Empty lines are skipped.
     *   - Format: KEY=value (split on first = only; values may contain =).
     *   - Keys must be uppercase alphanumeric + underscore only.
     *   - Values already set in the server environment are NOT overwritten.
     *     (Allows server-level / CI environment variables to take precedence.)
     *
     * This parser is intentionally minimal — only raw string population.
     * Type casting is handled by env() (INIT-005) when values are accessed.
     *
     * @return void
     */
    private function loadEnvironment(): void
    {
        $envFile = ROOT_PATH . DIRECTORY_SEPARATOR . '.env';

        if (!file_exists($envFile) || !is_readable($envFile)) {
            // RC001-O02: If .env is missing and environment variables are not set, halt execution with deployment error page
            if (empty($_ENV['DB_HOST']) && getenv('DB_HOST') === false) {
                http_response_code(500);
                header('Content-Type: text/html; charset=UTF-8');
                echo '<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Configuration Error — INVEETAIRE</title>
    <style>
        body { font-family: ui-sans-serif, system-ui, -apple-system, sans-serif; background-color: #FAF8F3; color: #232323; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; padding: 1.5rem; }
        .card { background: #ffffff; border: 1px solid #e2e8f0; border-radius: 1rem; padding: 2.5rem; max-width: 500px; width: 100%; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }
        .badge { background: #fef2f2; color: #dc2626; border: 1px solid #fee2e2; font-size: 0.75rem; font-weight: 700; padding: 0.25rem 0.75rem; border-radius: 9999px; display: inline-block; text-transform: uppercase; margin-bottom: 1rem; }
        h1 { font-size: 1.5rem; font-weight: 700; margin: 0 0 1rem 0; color: #1e293b; }
        p { color: #64748b; font-size: 0.875rem; line-height: 1.5; margin: 0 0 1.5rem 0; }
        code { background: #f1f5f9; padding: 0.2rem 0.4rem; border-radius: 0.25rem; font-size: 0.8125rem; color: #0f172a; font-family: monospace; }
        .instructions { background: #f8fafc; border-left: 4px solid #3b82f6; padding: 1rem; border-radius: 0 0.5rem 0.5rem 0; font-size: 0.8125rem; color: #334155; }
    </style>
</head>
<body>
    <div class="card">
        <span class="badge">Deployment Warning</span>
        <h1>Environment Configuration Missing</h1>
        <p>The <code>.env</code> configuration file was not found in the application root directory.</p>
        <div class="instructions">
            <strong>Deployment Action Required:</strong><br>
            Copy <code>.env.example</code> to <code>.env</code> in your root folder and configure your database and app credentials.
        </div>
    </div>
</body>
</html>';
                exit;
            }
            return;
        }

        $lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

        if ($lines === false) {
            return;
        }

        foreach ($lines as $line) {
            $line = trim($line);

            // Skip comment lines and blank lines.
            if ($line === '' || $line[0] === '#') {
                continue;
            }

            // Skip lines without an = sign.
            if (strpos($line, '=') === false) {
                continue;
            }

            // Split on first = only — values may contain = signs.
            [$key, $value] = explode('=', $line, 2);
            $key   = trim($key);
            $value = trim($value);

            // Validate key format: uppercase letters, digits, underscores only.
            // Prevents unexpected keys or injection from a malformed .env file.
            if (!preg_match('/^[A-Z][A-Z0-9_]*$/', $key)) {
                continue;
            }

            // Do not overwrite values already present in the environment.
            if (!array_key_exists($key, $_ENV)) {
                $_ENV[$key] = $value;
            }
        }
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STEP 2 — HELPERS
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Require global helper function files.
     *
     * These files define global functions (env, config) — not classes.
     * They cannot be autoloaded by the Autoloader and must be required
     * explicitly. Must run AFTER loadEnvironment() so that env() can
     * immediately access the populated $_ENV array.
     *
     * @return void
     */
    private function loadHelpers(): void
    {
        require_once ROOT_PATH . '/app/helpers/env.php';
        require_once ROOT_PATH . '/app/helpers/config.php';
        require_once ROOT_PATH . '/app/helpers/csrf_field.php';      // INIT-010
        require_once ROOT_PATH . '/app/helpers/escape_html.php';     // INIT-011
        require_once ROOT_PATH . '/app/helpers/escape_javascript.php'; // BETA-001: JS string escaping
        require_once ROOT_PATH . '/app/helpers/url.php';
    }


    // ─────────────────────────────────────────────────────────────────────────
    // STEP 3 — ERROR REPORTING
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Configure PHP's error reporting based on APP_DEBUG.
     *
     * Development (APP_DEBUG=true):
     *   - Report all errors.
     *   - Display errors in the browser.
     *
     * Production (APP_DEBUG=false):
     *   - Report all errors (for logging).
     *   - DO NOT display errors to the browser.
     *   - Enable error logging to the server error log.
     *     (ErrorHandler in INIT-006 routes errors to storage/logs/)
     *
     * @return void
     */
    private function configureErrorReporting(): void
    {
        $debug = env('APP_DEBUG', false);

        error_reporting(E_ALL);

        if ($debug) {
            ini_set('display_errors', '1');
            ini_set('display_startup_errors', '1');
        } else {
            ini_set('display_errors', '0');
            ini_set('display_startup_errors', '0');
            ini_set('log_errors', '1');
        }
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STEP 4 — ERROR HANDLERS
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Register the global error, exception, and shutdown handlers.
     *
     * Delegates to ErrorHandler::register() (INIT-006), which installs:
     *   - set_error_handler()         → converts PHP errors to ErrorException
     *   - set_exception_handler()     → logs and renders uncaught Throwables
     *   - register_shutdown_function() → catches fatal errors
     *
     * @return void
     */
    private function registerErrorHandlers(): void
    {
        ErrorHandler::register();
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STEP 5 — TIMEZONE
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Set the default PHP timezone.
     *
     * All application timestamps are stored in UTC (DBP v1.0 Ch.3).
     * Display formatting is handled by the View layer, not by PHP's timezone.
     *
     * @return void
     */
    private function setTimezone(): void
    {
        $timezone = config('app.timezone', 'UTC');
        date_default_timezone_set(is_string($timezone) ? $timezone : 'UTC');
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STEP 7 — SESSION (INIT-010)
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Start the PHP session with the security settings from config/session.php.
     *
     * Delegated to Session::start() (INIT-010) which handles:
     *   - session_name()             → inveetaire_session
     *   - session_save_path()        → storage/sessions/
     *   - session_set_cookie_params() → httponly, secure, samesite, path, domain
     *   - session_start()
     *
     * Must run after setTimezone() and before Application::handleRequest().
     * Running after error handlers ensures session errors are caught and logged.
     *
     * @return void
     */
    private function startSession(): void
    {
        Session::start();
    }
}
