<?php
declare(strict_types=1);

defined('ROOT_PATH') || define('ROOT_PATH', dirname(__DIR__));
require_once ROOT_PATH . '/app/config.php';

$logDirectory = ROOT_PATH . '/storage/logs';
if (!is_dir($logDirectory)) {
    @mkdir($logDirectory, 0750, true);
}
ini_set('log_errors', '1');
if (is_dir($logDirectory) && is_writable($logDirectory)) {
    ini_set('error_log', $logDirectory . '/app.log');
}
ini_set('display_errors', APP_DEBUG ? '1' : '0');
ini_set('display_startup_errors', APP_DEBUG ? '1' : '0');
ini_set('expose_php', '0');
error_reporting(E_ALL);

try {
    $requestId = bin2hex(random_bytes(8));
} catch (Throwable) {
    $requestId = substr(hash('sha256', uniqid('', true)), 0, 16);
}
defined('REQUEST_ID') || define('REQUEST_ID', $requestId);

$isHttps = static function (): bool {
    if (!empty($_SERVER['HTTPS']) && strtolower((string) $_SERVER['HTTPS']) !== 'off') {
        return true;
    }
    if ((int) ($_SERVER['SERVER_PORT'] ?? 0) === 443) {
        return true;
    }
    if (TRUST_PROXY_HEADERS) {
        $forwardedProto = strtolower(trim(explode(',', (string) ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''))[0] ?? ''));
        if ($forwardedProto === 'https') {
            return true;
        }
        if (strtolower((string) ($_SERVER['HTTP_X_FORWARDED_SSL'] ?? '')) === 'on') {
            return true;
        }
    }
    return false;
};

$secureRequest = $isHttps();
if (FORCE_HTTPS && PHP_SAPI !== 'cli' && !$secureRequest && APP_URL !== '' && str_starts_with(strtolower(APP_URL), 'https://')) {
    $target = APP_URL . '/' . ltrim((string) ($_SERVER['REQUEST_URI'] ?? ''), '/');
    header('Location: ' . $target, true, 301);
    exit;
}

if (PHP_SAPI !== 'cli' && !headers_sent()) {
    header('X-Request-ID: ' . REQUEST_ID);
    header('X-Content-Type-Options: nosniff');
    header('X-Frame-Options: SAMEORIGIN');
    header('Referrer-Policy: strict-origin-when-cross-origin');
    header('Permissions-Policy: camera=(self), microphone=(), geolocation=(), payment=(self)');
    header("Content-Security-Policy: base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self' https://sandbox.sslcommerz.com https://securepay.sslcommerz.com");
    header('Cross-Origin-Opener-Policy: same-origin');
    header('X-Permitted-Cross-Domain-Policies: none');
    if ($secureRequest) {
        header('Strict-Transport-Security: max-age=31536000');
    }
}

if (session_status() === PHP_SESSION_NONE) {
    ini_set('session.use_strict_mode', '1');
    ini_set('session.use_only_cookies', '1');
    ini_set('session.cookie_httponly', '1');
    ini_set('session.cookie_samesite', 'Lax');
    ini_set('session.gc_maxlifetime', (string) SESSION_ABSOLUTE_TIMEOUT);
    session_name(SESSION_NAME);
    session_set_cookie_params([
        'lifetime' => 0,
        'path' => '/',
        'domain' => '',
        'secure' => $secureRequest || FORCE_HTTPS,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
    session_start();
}

spl_autoload_register(static function (string $class): void {
    $prefix = 'App\\';
    if (strpos($class, $prefix) !== 0) {
        return;
    }
    $file = ROOT_PATH . '/app/' . str_replace('\\', '/', substr($class, strlen($prefix))) . '.php';
    if (is_file($file)) {
        require_once $file;
    }
});

require_once ROOT_PATH . '/app/helpers.php';
require_once ROOT_PATH . '/app/modules.php';

$renderFatal = static function (Throwable $exception): void {
    $message = sprintf(
        '[%s] Unhandled %s: %s in %s:%d',
        REQUEST_ID,
        get_class($exception),
        $exception->getMessage(),
        $exception->getFile(),
        $exception->getLine()
    );
    error_log($message . "\n" . $exception->getTraceAsString());

    if (headers_sent()) {
        return;
    }
    http_response_code(500);
    $path = str_replace('\\', '/', (string) ($_SERVER['SCRIPT_NAME'] ?? ''));
    $accept = strtolower((string) ($_SERVER['HTTP_ACCEPT'] ?? ''));
    $expectsJson = str_contains($path, '/api/') || str_contains($accept, 'application/json');
    if ($expectsJson) {
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode([
            'ok' => false,
            'message' => APP_DEBUG ? $exception->getMessage() : 'The request could not be completed.',
            'request_id' => REQUEST_ID,
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return;
    }
    header('Content-Type: text/html; charset=utf-8');
    $detail = APP_DEBUG ? '<pre>' . htmlspecialchars((string) $exception, ENT_QUOTES, 'UTF-8') . '</pre>' : '';
    echo '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Server Error</title><style>body{font-family:system-ui;background:#f6f8fb;margin:0;padding:40px}.box{max-width:720px;margin:auto;background:#fff;border-radius:14px;padding:28px;box-shadow:0 8px 30px #0001}code{background:#eef2ff;padding:3px 6px;border-radius:5px}</style></head><body><div class="box"><h1>Something went wrong</h1><p>The server could not complete this request. Reference: <code>' . htmlspecialchars(REQUEST_ID, ENT_QUOTES, 'UTF-8') . '</code></p>' . $detail . '</div></body></html>';
};

set_exception_handler($renderFatal);
register_shutdown_function(static function () use ($renderFatal): void {
    $error = error_get_last();
    if (!$error || !in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        return;
    }
    $renderFatal(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']));
});

if (!empty($_SESSION['user_id'])) {
    header('Cache-Control: no-store, private, max-age=0');
    header('Pragma: no-cache');
    App\Core\Auth::validateSession();

    if (App\Core\Auth::requiresPasswordChange() && PHP_SAPI !== 'cli') {
        $script = str_replace('\\', '/', (string)($_SERVER['SCRIPT_NAME'] ?? ''));
        $allowed = str_ends_with($script, '/public/change-password.php')
            || str_ends_with($script, '/public/logout.php')
            || str_ends_with($script, '/admin/logout.php');
        if (!$allowed) {
            $accept = strtolower((string)($_SERVER['HTTP_ACCEPT'] ?? ''));
            if (str_contains($script, '/api/') || str_contains($accept, 'application/json')) {
                http_response_code(428);
                header('Content-Type: application/json; charset=utf-8');
                echo json_encode(['ok'=>false,'message'=>'Change the temporary password before continuing.','redirect'=>url('public/change-password.php')]);
                exit;
            }
            redirect('public/change-password.php');
        }
    }
}
