<?php

declare(strict_types=1);

namespace Tests\Framework\Mcp\Tools;

use App\Framework\DI\Container;
use App\Framework\DI\DefaultContainer;
use App\Framework\Discovery\UnifiedDiscoveryService;
use App\Framework\Mcp\Tools\FrameworkTools;
use App\Framework\Router\CompiledRoutes;
use Mockery;

describe('FrameworkTools MCP Integration', function () {
    beforeEach(function () {
        $this->container = new DefaultContainer();
        $this->discoveryService = Mockery::mock(UnifiedDiscoveryService::class);
        $this->compiledRoutes = Mockery::mock(CompiledRoutes::class);

        $this->frameworkTools = new FrameworkTools(
            $this->container,
            $this->discoveryService,
            $this->compiledRoutes
        );
    });

    afterEach(function () {
        Mockery::close();
    });

    it('can analyze routes', function () {
        $this->compiledRoutes
            ->shouldReceive('getStaticRoutes')
            ->once()
            ->andReturn([
                '/admin' => ['handler' => 'AdminController@dashboard'],
                '/api/users' => ['handler' => 'UserController@index'],
            ]);

        $this->compiledRoutes
            ->shouldReceive('getNamedRoutes')
            ->once()
            ->andReturn([
                'admin.dashboard' => '/admin',
                'api.users.index' => '/api/users',
            ]);

        $result = $this->frameworkTools->analyzeRoutes();

        expect($result)->toBeArray();
        expect($result)->toHaveKey('named_routes');
        expect($result)->toHaveKey('total_routes');
        expect($result['total_routes'])->toBe(2);
    });

    it('can analyze container bindings', function () {
        // Register some services in the container
        $this->container->singleton('TestService', function () {
            return new \stdClass();
        });

        $result = $this->frameworkTools->analyzeContainerBindings();

        expect($result)->toBeArray();
        expect($result)->toHaveKey('total_bindings');
        expect($result)->toHaveKey('bindings');
        expect($result['total_bindings'])->toBeGreaterThan(0);
    });

    it('can discover attributes', function () {
        $mockRegistry = Mockery::mock(\App\Framework\Discovery\Results\DiscoveryRegistry::class);
        $mockAttributeRegistry = Mockery::mock(\App\Framework\Discovery\Results\AttributeRegistry::class);

        $mockRegistry->attributes = $mockAttributeRegistry;

        $mockAttributeRegistry
            ->shouldReceive('get')
            ->with('App\\Framework\\Mcp\\McpTool')
            ->once()
            ->andReturn([
                ['className' => 'TestClass', 'methodName' => 'testMethod'],
                ['className' => 'AnotherClass', 'methodName' => 'anotherMethod'],
            ]);

        $this->discoveryService
            ->shouldReceive('discover')
            ->once()
            ->andReturn($mockRegistry);

        $result = $this->frameworkTools->discoverAttributes('App\\Framework\\Mcp\\McpTool');

        expect($result)->toBeArray();
        expect($result)->toHaveKey('attribute_class');
        expect($result)->toHaveKey('count');
        expect($result)->toHaveKey('discoveries');
        expect($result['attribute_class'])->toBe('App\\Framework\\Mcp\\McpTool');
        expect($result['count'])->toBe(2);
        expect($result['discoveries'])->toHaveCount(2);
    });

    it('handles discovery errors gracefully', function () {
        $this->discoveryService
            ->shouldReceive('discover')
            ->once()
            ->andThrow(new \Exception('Discovery failed'));

        $result = $this->frameworkTools->discoverAttributes('NonExistentAttribute');

        expect($result)->toBeArray();
        expect($result)->toHaveKey('error');
        expect($result)->toHaveKey('attribute_class');
        expect($result['error'])->toBe('Discovery failed');
        expect($result['attribute_class'])->toBe('NonExistentAttribute');
    });

    it('performs framework health check', function () {
        $result = $this->frameworkTools->frameworkHealthCheck();

        expect($result)->toBeArray();
        expect($result)->toHaveKey('status');
        expect($result)->toHaveKey('components');
        expect($result)->toHaveKey('timestamp');
        expect($result['status'])->toBe('completed');
        expect($result['components'])->toHaveKey('container');
        expect($result['components'])->toHaveKey('discovery_service');
    });

    it('lists framework modules', function () {
        $result = $this->frameworkTools->listFrameworkModules();

        expect($result)->toBeArray();
        expect($result)->toHaveKey('core_modules');
        expect($result)->toHaveKey('total_modules');
        expect($result['core_modules'])->toBeArray();
        expect($result['total_modules'])->toBeGreaterThan(0);
    });

    it('validates container health in health check', function () {
        $result = $this->frameworkTools->frameworkHealthCheck();

        expect($result['components']['container'])->toBe('healthy');
    });

    it('validates discovery service health in health check', function () {
        $result = $this->frameworkTools->frameworkHealthCheck();

        expect($result['components']['discovery_service'])->toBe('healthy');
    });

    it('handles container errors in health check', function () {
        // Create a broken container scenario by triggering an error
        $brokenContainer = Mockery::mock(Container::class);
        $brokenContainer
            ->shouldReceive('get')
            ->andThrow(new \Exception('Container error'));

        $frameworkTools = new FrameworkTools(
            $brokenContainer,
            $this->discoveryService,
            $this->compiledRoutes
        );

        $result = $frameworkTools->frameworkHealthCheck();

        expect($result['components']['container'])->toContain('error');
    });

    it('limits discovery results to prevent overwhelming output', function () {
        $mockRegistry = Mockery::mock(\App\Framework\Discovery\Results\DiscoveryRegistry::class);
        $mockAttributeRegistry = Mockery::mock(\App\Framework\Discovery\Results\AttributeRegistry::class);

        $mockRegistry->attributes = $mockAttributeRegistry;

        // Create 15 mock results
        $manyResults = array_fill(0, 15, ['className' => 'TestClass', 'methodName' => 'testMethod']);

        $mockAttributeRegistry
            ->shouldReceive('get')
            ->once()
            ->andReturn($manyResults);

        $this->discoveryService
            ->shouldReceive('discover')
            ->once()
            ->andReturn($mockRegistry);

        $result = $this->frameworkTools->discoverAttributes('SomeAttribute');

        expect($result['total_found'])->toBe(15);
        expect($result['discoveries'])->toHaveCount(10); // Limited to 10
        expect($result['count'])->toBe(15); // But count shows total
    });
});
