<?php

declare(strict_types=1);

namespace PHPyh\ServiceDumperBundle;

use PHPUnit\Framework\TestCase;
use PHPyh\ServiceDumperBundle\ServiceDumper\SymfonyVarDumperServiceDumper;
use PHPyh\ServiceDumperBundle\ServiceDumper\VarDumpServiceDumper;
use PHPyh\ServiceDumperBundle\ServiceDumper\XdebugServiceDumper;
use PHPyh\ServiceDumperBundle\ServiceFinder\BasicServiceFinder;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
 * @covers \PHPyh\ServiceDumperBundle\ServiceDumperBundle
 */
final class ServiceDumperBundleConfigurationTest extends TestCase
{
    public function testItUsesSymfonyVarDumperByDefault(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Definition(SymfonyVarDumperServiceDumper::class), $commandDefinition->getArgument(1));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    public function testServiceDumperCanBeSetToVarDump(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->loadFromExtension('phpyh_service_dumper', ['service_dumper' => 'var_dump']);

            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Definition(VarDumpServiceDumper::class), $commandDefinition->getArgument(1));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    public function testServiceDumperCanBeSetToXdebug(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->loadFromExtension('phpyh_service_dumper', ['service_dumper' => 'xdebug']);

            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Definition(XdebugServiceDumper::class), $commandDefinition->getArgument(1));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    public function testServiceDumperCanBeSetToAnyServiceId(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->register('test', \stdClass::class);
            $container->loadFromExtension('phpyh_service_dumper', ['service_dumper' => 'test']);

            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Reference('test'), $commandDefinition->getArgument(1));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    public function testItUsesBasicServiceFinderByDefault(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Definition(BasicServiceFinder::class), $commandDefinition->getArgument(2));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    public function testServiceFinderCanBeSetToAnyServiceId(): void
    {
        $kernel = new TestKernel([ServiceDumperBundle::class], static function (ContainerBuilder $container): void {
            $container->register('test', \stdClass::class);
            $container->loadFromExtension('phpyh_service_dumper', ['service_finder' => 'test']);

            $container->addCompilerPass(new class () implements CompilerPassInterface {
                public function process(ContainerBuilder $container): void
                {
                    $commandDefinition = $container->getDefinition(DebugDumpServiceCommand::class);

                    TestCase::assertEquals(new Reference('test'), $commandDefinition->getArgument(2));
                }
            }, PassConfig::TYPE_AFTER_REMOVING);
        });
        $kernel->boot();
    }

    /**
     * @testWith ["debug:dump-service"]
     *           ["service"]
     */
    public function testCommandCanBeCalled(string $name): void
    {
        $cli = new Application(new TestKernel([ServiceDumperBundle::class]));

        $command = $cli->get($name);

        self::assertSame('debug:dump-service', $command->getName());
    }
}
