#!/opt/cpanel/ea-php85/root/usr/bin/php
<?php

declare(strict_types=1);

/**
 * Contextia MCP server — stdio transport.
 *
 * Reads newline-delimited JSON-RPC 2.0 from STDIN and writes responses to
 * STDOUT (blocking loop). STDOUT carries JSON-RPC ONLY; diagnostics go to
 * STDERR and the application log (storage/logs via FileLogger).
 *
 * Auth: the CONTEXTIA_API_KEY environment variable must hold a valid API key
 * (same keys as the HTTP API). The whole session runs in the tenant/project
 * context of that key. The process exits with a clear error when the key is
 * missing or invalid — the key itself is never echoed or logged.
 */

use App\Domain\ApiKey\AuthenticationException;
use App\MCP\Server;
use App\Support\Bootstrap;

require dirname(__DIR__) . '/vendor/autoload.php';

if (PHP_SAPI !== 'cli') {
    fwrite(STDERR, "This script must be run from the command line.\n");
    exit(1);
}

$bootstrap = new Bootstrap(dirname(__DIR__));

$plaintextKey = getenv('CONTEXTIA_API_KEY');
if (!is_string($plaintextKey) || trim($plaintextKey) === '') {
    fwrite(STDERR, "CONTEXTIA_API_KEY environment variable is required.\n");
    fwrite(STDERR, "Export a valid Contextia API key before starting the stdio MCP server, e.g.:\n");
    fwrite(STDERR, "  CONTEXTIA_API_KEY=<api key> bin/mcp-server\n");
    exit(1);
}

try {
    $auth = $bootstrap->apiKeyService()->authenticate($plaintextKey);
} catch (AuthenticationException) {
    fwrite(STDERR, "CONTEXTIA_API_KEY is not a valid, active API key. Create one with:\n");
    fwrite(STDERR, "  bin/mcp apikey:create --tenant=<slug> --project=<slug> --name=<name>\n");
    exit(1);
} catch (Throwable $e) {
    // Bootstrap/database failure: never leak connection details to the client.
    fwrite(STDERR, "Could not start the MCP server (configuration or database unavailable).\n");
    exit(1);
}
unset($plaintextKey);

$logger = $bootstrap->logger();
$server = $bootstrap->mcpServer();

$logger->info('MCP stdio server started', [
    'tenant_id' => $auth->tenant->id,
    'project_id' => $auth->project?->id,
    'scope' => $auth->scope,
    'api_key_id' => $auth->apiKey->id,
]);

$emit = static function (array $response): void {
    fwrite(STDOUT, json_encode($response, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n");
    fflush(STDOUT);
};

while (($line = fgets(STDIN)) !== false) {
    $line = trim($line);
    if ($line === '') {
        continue;
    }

    $decoded = json_decode($line, true);
    if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) {
        $emit(Server::error(null, Server::JSONRPC_PARSE_ERROR, 'Parse error: line is not valid JSON.'));
        continue;
    }

    // Server::handle() catches everything request-scoped; this guard only
    // covers truly unexpected failures so the loop never dies mid-session.
    try {
        $response = $server->handle($decoded, $auth);
    } catch (Throwable $e) {
        $logger->error('MCP stdio loop error', ['error_class' => $e::class]);
        $response = Server::error(null, Server::JSONRPC_INTERNAL_ERROR, 'Internal error.');
    }

    if ($response !== null) {
        $emit($response);
    }
}

$logger->info('MCP stdio server stopped', [
    'tenant_id' => $auth->tenant->id,
    'project_id' => $auth->project?->id,
    'scope' => $auth->scope,
]);
exit(0);
