<?php

/**
 * Protección CSRF para operaciones autenticadas de ICYLAB OS.
 * Debe cargarse después de iniciar la sesión.
 */

if (!function_exists('csrf_token')) {
    function csrf_token(): string
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            throw new RuntimeException('La sesión debe estar activa antes de generar el token CSRF.');
        }

        $token = $_SESSION['_csrf_token'] ?? '';
        if (!is_string($token) || strlen($token) < 64) {
            $token = bin2hex(random_bytes(32));
            $_SESSION['_csrf_token'] = $token;
            $_SESSION['_csrf_token_created_at'] = time();
        }
        return $token;
    }
}

if (!function_exists('csrf_request_token')) {
    function csrf_request_token(): string
    {
        $header = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
        if (is_string($header) && trim($header) !== '') {
            return trim($header);
        }
        $form = $_POST['_csrf_token'] ?? '';
        return is_string($form) ? trim($form) : '';
    }
}

if (!function_exists('csrf_validate_request')) {
    function csrf_validate_request(): bool
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            return false;
        }
        $expected = $_SESSION['_csrf_token'] ?? '';
        $actual = csrf_request_token();
        return is_string($expected)
            && strlen($expected) >= 64
            && $actual !== ''
            && hash_equals($expected, $actual);
    }
}

if (!function_exists('csrf_require_valid_request')) {
    function csrf_require_valid_request(): void
    {
        $method = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET'));
        if (!in_array($method, array('POST', 'PUT', 'PATCH', 'DELETE'), true)) {
            return;
        }
        if (csrf_validate_request()) {
            return;
        }

        http_response_code(419);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(array(
            'success' => false,
            'message' => 'La sesión de seguridad expiró. Recarga la página e intenta nuevamente.',
            'code' => 'CSRF_TOKEN_INVALID'
        ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}

if (!function_exists('csrf_normalize_origin')) {
    function csrf_normalize_origin($value): string
    {
        $value = trim((string)$value);
        if ($value === '' || strtolower($value) === 'null') {
            return '';
        }

        $parts = parse_url($value);
        if (!is_array($parts) || empty($parts['scheme']) || empty($parts['host'])) {
            return '';
        }

        $scheme = strtolower((string)$parts['scheme']);
        $host = strtolower((string)$parts['host']);
        if (!in_array($scheme, array('http', 'https'), true)) {
            return '';
        }

        $origin = $scheme . '://' . $host;
        if (!empty($parts['port'])) {
            $origin .= ':' . (int)$parts['port'];
        }
        return $origin;
    }
}

if (!function_exists('csrf_expected_origins')) {
    function csrf_expected_origins(): array
    {
        $origins = array();
        if (defined('APP_URL')) {
            $configured = csrf_normalize_origin(APP_URL);
            if ($configured !== '') {
                $origins[] = $configured;
            }
        }

        // Facilita staging/local sin confiar en valores Host arbitrarios.
        $host = strtolower(trim((string)($_SERVER['HTTP_HOST'] ?? '')));
        if ($host !== '' && preg_match('/^[a-z0-9.-]+(?::[0-9]{1,5})?$/', $host)) {
            $https = strtolower((string)($_SERVER['HTTPS'] ?? ''));
            $scheme = ($https !== '' && $https !== 'off') ? 'https' : 'http';
            $origins[] = $scheme . '://' . $host;
        }

        return array_values(array_unique($origins));
    }
}

if (!function_exists('csrf_require_same_origin_request')) {
    function csrf_require_same_origin_request(): void
    {
        if (PHP_SAPI === 'cli') {
            return;
        }

        $method = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET'));
        if (!in_array($method, array('POST', 'PUT', 'PATCH', 'DELETE'), true)) {
            return;
        }

        $source = trim((string)($_SERVER['HTTP_ORIGIN'] ?? ''));
        if ($source === '') {
            $source = trim((string)($_SERVER['HTTP_REFERER'] ?? ''));
        }

        $actual = csrf_normalize_origin($source);
        if ($actual !== '' && in_array($actual, csrf_expected_origins(), true)) {
            return;
        }

        http_response_code(403);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(array(
            'success' => false,
            'message' => 'Origen de solicitud no autorizado. Recarga la página e intenta nuevamente.',
            'code' => 'REQUEST_ORIGIN_INVALID'
        ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}
