<?php

declare(strict_types=1);

use App\Application\GraphQL\NotificationSubscriptions;
use App\Framework\GraphQL\Attributes\GraphQLSubscription;
use App\Framework\GraphQL\Schema\SchemaBuilder;
use App\Framework\GraphQL\Subscriptions\SubscriptionId;
use App\Framework\GraphQL\Subscriptions\SubscriptionRegistry;
use App\Framework\Http\WebSocketConnectionInterface;

describe('GraphQL Subscriptions', function () {
    beforeEach(function () {
        $this->registry = new SubscriptionRegistry();

        // Create mock WebSocket connection using Mockery
        $this->connection = Mockery::mock(WebSocketConnectionInterface::class);
        $this->connection->shouldReceive('getId')->andReturn('test-connection-1');
        $this->connection->shouldReceive('isConnected')->andReturn(true);
        $this->connection->shouldReceive('sendJson')->andReturnTrue();
        $this->connection->shouldReceive('setAttribute')->andReturnNull();
        $this->connection->shouldReceive('getAttribute')->andReturn(null);

        $this->sentMessages = [];
    });

    it('can register and retrieve subscriptions', function () {
        $id = SubscriptionId::generate();

        $this->registry->register(
            $id,
            $this->connection,
            'notificationReceived',
            ['userId' => '123']
        );

        $subscriptions = $this->registry->getByName('notificationReceived');

        expect($subscriptions)->toHaveCount(1);
        expect($subscriptions[0]['id']->toString())->toBe($id->toString());
        expect($subscriptions[0]['variables']['userId'])->toBe('123');
    });

    it('can unregister subscriptions', function () {
        $id = SubscriptionId::generate();

        $this->registry->register(
            $id,
            $this->connection,
            'notificationReceived',
            ['userId' => '123']
        );

        expect($this->registry->getByName('notificationReceived'))->toHaveCount(1);

        $this->registry->unregister($id);

        expect($this->registry->getByName('notificationReceived'))->toHaveCount(0);
    });

    it('can cleanup subscriptions by connection', function () {
        $id1 = SubscriptionId::generate();
        $id2 = SubscriptionId::generate();

        $this->registry->register(
            $id1,
            $this->connection,
            'notificationReceived',
            ['userId' => '123']
        );

        $this->registry->register(
            $id2,
            $this->connection,
            'orderStatusChanged',
            ['orderId' => 'order-1']
        );

        expect($this->registry->getByName('notificationReceived'))->toHaveCount(1);
        expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(1);

        $this->registry->removeByConnection($this->connection);

        expect($this->registry->getByName('notificationReceived'))->toHaveCount(0);
        expect($this->registry->getByName('orderStatusChanged'))->toHaveCount(0);
    });

    it('provides subscription statistics', function () {
        $this->registry->register(
            SubscriptionId::generate(),
            $this->connection,
            'notificationReceived',
            ['userId' => '123']
        );

        $this->registry->register(
            SubscriptionId::generate(),
            $this->connection,
            'orderStatusChanged',
            ['orderId' => 'order-1']
        );

        $stats = $this->registry->getStats();

        expect($stats['total_subscriptions'])->toBe(2);
        expect($stats['unique_connections'])->toBe(1);
        expect($stats['subscriptions_by_type']['notificationReceived'])->toBe(1);
        expect($stats['subscriptions_by_type']['orderStatusChanged'])->toBe(1);
    });

    it('discovers GraphQLSubscription classes', function () {
        $reflection = new ReflectionClass(NotificationSubscriptions::class);
        $attribute = $reflection->getAttributes(GraphQLSubscription::class)[0] ?? null;

        expect($attribute)->not->toBeNull();

        $instance = $attribute->newInstance();
        expect($instance->description)->toBe('Real-time notification subscriptions');
    });

    it('builds subscription fields in schema', function () {
        // Create simple container for testing
        $container = new \App\Framework\DI\DefaultContainer();

        $typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver();
        $schemaBuilder = new SchemaBuilder($container, $typeResolver);

        $schema = $schemaBuilder->build([
            NotificationSubscriptions::class,
        ]);

        expect($schema->subscriptions)->toHaveCount(3);
        expect($schema->getSubscription('notificationReceived'))->not->toBeNull();
        expect($schema->getSubscription('orderStatusChanged'))->not->toBeNull();
        expect($schema->getSubscription('systemAnnouncement'))->not->toBeNull();
    });

    it('generates correct SDL for subscriptions', function () {
        // Create simple container for testing
        $container = new \App\Framework\DI\DefaultContainer();

        $typeResolver = new \App\Framework\GraphQL\Schema\TypeResolver();
        $schemaBuilder = new SchemaBuilder($container, $typeResolver);

        $schema = $schemaBuilder->build([
            NotificationSubscriptions::class,
        ]);

        $sdl = $schema->toSDL();

        expect($sdl)->toContain('type Subscription {');
        expect($sdl)->toContain('notificationReceived');
        expect($sdl)->toContain('orderStatusChanged');
        expect($sdl)->toContain('systemAnnouncement');
    });
});
