<?php

namespace Core\System;

class Csrf
{
    public static function token(): string
    {
        if (empty($_SESSION['_csrf'])) {
            $_SESSION['_csrf'] = bin2hex(random_bytes(32));
        }

        return $_SESSION['_csrf'];
    }

    public static function field(): string
    {
        $token = self::token();

        return '<input type="hidden" name="_csrf" value="' .
            htmlspecialchars($token, ENT_QUOTES, 'UTF-8') .
            '">';
    }

    public static function check(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

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

        $uri = parse_url((string)($_SERVER['REQUEST_URI'] ?? '/'), PHP_URL_PATH) ?: '/';
        if (self::isInstallerRequest($uri)) {
            return;
        }

        $token = self::extractToken();
        if (
            $token === '' ||
            empty($_SESSION['_csrf']) ||
            !hash_equals((string) $_SESSION['_csrf'], $token)
        ) {
            http_response_code(419);
            // Use the translation helper if available, otherwise fall back to a neutral message
            $msg = function_exists('__') ? __('error.csrf_mismatch', 'Request expired. Please go back and try again.') : 'Request expired. Please go back and try again.';

            if (self::expectsJson()) {
                header('Content-Type: application/json; charset=utf-8');
                echo json_encode([
                    'success' => false,
                    'message' => $msg,
                    'code' => 'csrf_mismatch',
                ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            } else {
                echo htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
            }
            exit;
        }
    }


    private static function expectsJson(): bool
    {
        $accept = strtolower((string)($_SERVER['HTTP_ACCEPT'] ?? ''));
        $requestedWith = strtolower((string)($_SERVER['HTTP_X_REQUESTED_WITH'] ?? ''));
        $contentType = strtolower((string)($_SERVER['CONTENT_TYPE'] ?? ''));

        return str_contains($accept, 'application/json')
            || $requestedWith === 'xmlhttprequest'
            || str_contains($contentType, 'application/json');
    }

    private static function extractToken(): string
    {
        $candidates = [
            $_POST['_csrf'] ?? '',
            $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '',
            $_SERVER['HTTP_X_CSRF'] ?? '',
            $_SERVER['REDIRECT_HTTP_X_CSRF_TOKEN'] ?? '',
        ];

        foreach ($candidates as $candidate) {
            if (is_string($candidate) && trim($candidate) !== '') {
                return trim($candidate);
            }
        }

        $raw = file_get_contents('php://input');
        if (is_string($raw) && $raw !== '') {
            $json = json_decode($raw, true);
            if (is_array($json) && !empty($json['_csrf']) && is_string($json['_csrf'])) {
                return trim($json['_csrf']);
            }

            parse_str($raw, $formData);
            if (!empty($formData['_csrf']) && is_string($formData['_csrf'])) {
                return trim($formData['_csrf']);
            }
        }

        return '';
    }

    private static function isInstallerRequest(string $uri): bool
    {
        if ($uri !== '/install' && !str_starts_with($uri, '/install/')) {
            return false;
        }

        return class_exists(InstallerGuard::class)
            && InstallerGuard::canRunInstaller();
    }
}
