<?php

declare(strict_types=1);

use PostService\Node\ApiException;
use PostService\Node\FileScanner;
use PostService\Node\HmacAuthenticator;

require_once dirname(__DIR__) . '/src/ApiException.php';
require_once dirname(__DIR__) . '/src/HmacAuthenticator.php';
require_once dirname(__DIR__) . '/src/FileFingerprint.php';
require_once dirname(__DIR__) . '/src/FileScanner.php';

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
header('X-Content-Type-Options: nosniff');

function respond(int $status, array $payload): never
{
    http_response_code($status);
    echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    exit;
}

try {
    $configFile = getenv('POST_SERVICE_NODE_CONFIG') ?: dirname(__DIR__) . '/config.php';
    if (!is_file($configFile)) {
        throw new RuntimeException('Node configuration is missing');
    }
    $config = require $configFile;
    if (!is_array($config)) {
        throw new RuntimeException('Node configuration is invalid');
    }

    $method = strtoupper($_SERVER['REQUEST_METHOD'] ?? '');
    if ($method === 'GET') {
        respond(200, [
            'ok' => true,
            'service' => 'post-filesystem-node',
            'version' => 1,
            'nodeId' => (string) ($config['node_id'] ?? ''),
        ]);
    }
    if ($method !== 'POST') {
        header('Allow: GET, POST');
        respond(405, ['ok' => false, 'error' => ['code' => 'method_not_allowed', 'message' => 'Use POST to scan']]);
    }

    $scannerConfig = $config['scanner'] ?? [];
    $maxRequestBytes = (int) ($scannerConfig['max_request_bytes'] ?? 16384);
    $contentLength = (int) ($_SERVER['CONTENT_LENGTH'] ?? 0);
    if ($contentLength > $maxRequestBytes) {
        throw new ApiException('Request body is too large', 'request_too_large', 413);
    }

    $body = file_get_contents('php://input');
    if (!is_string($body) || strlen($body) > $maxRequestBytes) {
        throw new ApiException('Request body is too large', 'request_too_large', 413);
    }

    $authenticator = new HmacAuthenticator(
        (string) ($config['node_id'] ?? ''),
        (string) ($config['hmac_secret'] ?? ''),
        (int) ($scannerConfig['max_clock_skew_seconds'] ?? 300)
    );
    $authenticator->authenticate($_SERVER, $body);

    try {
        $request = json_decode($body, true, 32, JSON_THROW_ON_ERROR);
    } catch (JsonException $exception) {
        throw new ApiException('Request body must be valid JSON', 'invalid_json');
    }
    if (!is_array($request)) {
        throw new ApiException('Request body must be a JSON object', 'invalid_json');
    }

    $configuredMaxFiles = (int) ($scannerConfig['max_files_per_request'] ?? 25);
    $maxFiles = max(1, min(
        $configuredMaxFiles,
        (int) ($request['maxFiles'] ?? $scannerConfig['default_files_per_request'] ?? 10)
    ));
    $configuredTimeBudget = (int) ($scannerConfig['max_time_budget_seconds'] ?? 22);
    $timeBudget = max(1, min(
        $configuredTimeBudget,
        (int) ($request['timeBudgetSeconds'] ?? $scannerConfig['default_time_budget_seconds'] ?? 18)
    ));

    $scanner = new FileScanner(
        $config['hosts'] ?? [],
        (int) ($scannerConfig['max_file_size'] ?? 2097152000)
    );
    $result = $scanner->scan($request, $maxFiles, $timeBudget);

    respond(200, ['ok' => true, 'nodeId' => (string) $config['node_id']] + $result);
} catch (ApiException $exception) {
    respond($exception->getHttpStatus(), [
        'ok' => false,
        'error' => ['code' => $exception->getErrorCode(), 'message' => $exception->getMessage()],
    ]);
} catch (Throwable $exception) {
    error_log('Post filesystem node error: ' . $exception->getMessage());
    respond(500, [
        'ok' => false,
        'error' => ['code' => 'internal_error', 'message' => 'The node could not complete the request'],
    ]);
}

