<?php

declare(strict_types=1);

namespace App\Controller;

use App\Agent\AgentRunner;
use App\Http\ClientIdResolver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Annotation\Route;

final readonly class AskSseController
{
    public function __construct(
        private AgentRunner $agentRunner,
        private ClientIdResolver $clientIdResolver,
    ) {
    }

    #[Route('/ask-sse', name: 'ask_sse', methods: ['POST'])]
    public function stream(Request $request): StreamedResponse
    {
        $data = json_decode($request->getContent(), true);
        $prompt = trim((string) ($data['prompt'] ?? ''));

        /**
         * Default:
         * - Browser chat uses budgeted recent context
         * - Full context must be explicitly requested
         */
        $includeFullContext = filter_var(
            $data['fullContext'] ?? false,
            FILTER_VALIDATE_BOOL
        );

        $cookieResponse = new Response();
        $clientId = $this->clientIdResolver->resolve($request, $cookieResponse);

        return new StreamedResponse(
            function () use ($prompt, $clientId, $cookieResponse, $includeFullContext): void {
                while (ob_get_level() > 0) {
                    ob_end_flush();
                }

                foreach ($cookieResponse->headers->getCookies() as $cookie) {
                    header('Set-Cookie: ' . $cookie, false);
                }

                echo "retry: 3000\n\n";
                flush();

                if ($prompt === '') {
                    $this->sendEvent('error', 'Empty prompt');
                    $this->sendEvent('done', '[DONE]');
                    return;
                }

                try {
                    foreach ($this->agentRunner->run($prompt, $clientId, $includeFullContext) as $chunk) {
                        $chunk = str_replace(["\r\n", "\r"], "\n", $chunk);
                        $this->sendData($chunk);
                    }
                } catch (\Throwable $e) {
                    $this->sendEvent(
                        'error',
                        '❌ Stream abgebrochen: ' . $e->getMessage()
                    );
                }

                $this->sendEvent('done', '[DONE]');
            },
            200,
            [
                'Content-Type' => 'text/event-stream; charset=utf-8',
                'Cache-Control' => 'no-cache, no-store, must-revalidate',
                'Connection' => 'keep-alive',
                'X-Accel-Buffering' => 'no',
            ]
        );
    }

    private function sendData(string $data): void
    {
        $lines = explode("\n", $data);

        foreach ($lines as $line) {
            echo 'data: ' . $line . "\n";
        }

        echo "\n\n";
        flush();
    }

    private function sendEvent(string $event, string $data): void
    {
        $safe = str_replace(["\r", "\n"], ' ', $data);

        echo "event: {$event}\n";
        echo "data: {$safe}\n\n";
        flush();
    }
}