<?php

/**
 * Copyright (c) D3 Data Development (Inh. Thomas Dartsch)
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 *
 * https://www.d3data.de
 *
 * @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
 * @author    D3 Data Development - Daniel Seifert <info@shopmodule.com>
 * @link      https://www.oxidmodule.com
 */

namespace D3\LoggerFactory\tests;

use D3\LoggerFactory\LoggerFactory;
use Generator;
use Monolog\Handler\BufferHandler;
use Monolog\Handler\DeduplicationHandler;
use Monolog\Handler\FingersCrossedHandler;
use Monolog\Handler\HandlerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use ReflectionException;

/**
 * @coversNothing
 */
trait SpecialHandlersTestTrait
{
    /**
     * @test
     * @covers \D3\LoggerFactory\LoggerFactory::applySpecialHandlers
     * @throws ReflectionException
     */
    public function testApplySpecialHandlers(): void
    {
        $sut = $this->getMockBuilder(LoggerFactory::class)
            ->onlyMethods(['applyBufferHandler', 'applyLogOnErrorOnlyHandler', 'applyMakeUniqueHandler'])
            ->getMock();
        $sut->expects($this->once())->method('applyBufferHandler');
        $sut->expects($this->once())->method('applyLogOnErrorOnlyHandler');
        $sut->expects($this->once())->method('applyMakeUniqueHandler');

        $handler = $this->getMockBuilder(StreamHandler::class)
                        ->disableOriginalConstructor()
                        ->getMock();

        $this->assertInstanceOf(
            HandlerInterface::class,
            $this->callMethod(
                $sut,
                'applySpecialHandlers',
                [$handler, []]
            )
        );
    }

    /**
     * @test
     * @throws ReflectionException
     * @covers \D3\LoggerFactory\LoggerFactory::setBuffering
     */
    public function testSetBuffering(): void
    {
        $sut = LoggerFactory::create();

        $handler = $this->getMockBuilder(StreamHandler::class)
                        ->disableOriginalConstructor()
                        ->getMock();

        $this->assertInstanceOf(
            BufferHandler::class,
            $this->callMethod(
                $sut,
                'setBuffering',
                [$handler]
            )
        );
    }

    /**
     * @test
     * @throws ReflectionException
     * @covers \D3\LoggerFactory\LoggerFactory::setLogItemsOnErrorOnly
     */
    public function testSetLogItemsOnErrorOnly(): void
    {
        $sut = LoggerFactory::create();

        $handler = $this->getMockBuilder(StreamHandler::class)
                        ->disableOriginalConstructor()
                        ->getMock();

        $this->assertInstanceOf(
            FingersCrossedHandler::class,
            $this->callMethod(
                $sut,
                'setLogItemsOnErrorOnly',
                [$handler]
            )
        );
    }

    /**
     * @test
     * @throws ReflectionException
     * @covers \D3\LoggerFactory\LoggerFactory::makeUnique
     */
    public function testMakeUnique(): void
    {
        $sut = LoggerFactory::create();

        $handler = $this->getMockBuilder(StreamHandler::class)
                        ->disableOriginalConstructor()
                        ->getMock();

        $this->assertInstanceOf(
            DeduplicationHandler::class,
            $this->callMethod(
                $sut,
                'makeUnique',
                [$handler]
            )
        );
    }

    /**
     * @test
     *
     * @param array  $configuration
     * @param string $expectedClass
     *
     * @return void
     * @throws ReflectionException
     * @covers       \D3\LoggerFactory\LoggerFactory::applyBufferHandler
     * @dataProvider applyBufferHandlerDataProvider
     */
    public function testApplyBufferHandler(array $configuration, string $expectedClass): void
    {
        $handler = $this->getMockBuilder(StreamHandler::class)
            ->disableOriginalConstructor()
            ->getMock();

        $sut = LoggerFactory::create();

        $this->assertInstanceOf(
            $expectedClass,
            $this->callMethod(
                $sut,
                'applyBufferHandler',
                [$configuration, $handler]
            )
        );
    }

    public static function applyBufferHandlerDataProvider(): Generator
    {
        yield 'empty config' => [[], StreamHandler::class];
        yield 'simple buffering' => [[LoggerFactory::SPECIAL_HANDLERS_BUFFERING], BufferHandler::class];
        yield 'advanced buffering' => [
            [LoggerFactory::SPECIAL_HANDLERS_BUFFERING   => [LoggerFactory::BUFFERING_OPTION_LIMIT => 10]],
            BufferHandler::class,
        ];
    }

    /**
     * @test
     *
     * @param array  $configuration
     * @param string $expectedClass
     *
     * @return void
     * @throws ReflectionException
     * @covers       \D3\LoggerFactory\LoggerFactory::applyLogOnErrorOnlyHandler
     * @dataProvider applyLogOnErrorOnlyHandlerDataProvider
     */
    public function testApplyLogOnErrorOnlyHandler(array $configuration, string $expectedClass): void
    {
        $handler = $this->getMockBuilder(StreamHandler::class)
            ->disableOriginalConstructor()
            ->getMock();

        $sut = LoggerFactory::create();

        $this->assertInstanceOf(
            $expectedClass,
            $this->callMethod(
                $sut,
                'applyLogOnErrorOnlyHandler',
                [$configuration, $handler]
            )
        );
    }

    public static function applyLogOnErrorOnlyHandlerDataProvider(): Generator
    {
        yield 'empty config' => [[], StreamHandler::class];
        yield 'simple logOnErrorOnly' => [[LoggerFactory::SPECIAL_HANDLERS_LOG_ON_ERROR_ONLY], FingersCrossedHandler::class];
        yield 'advanced logOnErrorOnly' => [
            [LoggerFactory::SPECIAL_HANDLERS_LOG_ON_ERROR_ONLY   => [LoggerFactory::LOGONERRORONLY_LEVEL => Logger::DEBUG]],
            FingersCrossedHandler::class,
        ];
    }

    /**
     * @test
     *
     * @param array  $configuration
     * @param string $expectedClass
     *
     * @return void
     * @throws ReflectionException
     * @covers       \D3\LoggerFactory\LoggerFactory::applyMakeUniqueHandler
     * @dataProvider applyMakeUniqueHandlerDataProvider
     */
    public function testApplyMakeUniqueHandler(array $configuration, string $expectedClass): void
    {
        $handler = $this->getMockBuilder(StreamHandler::class)
            ->disableOriginalConstructor()
            ->getMock();

        $sut = LoggerFactory::create();

        $this->assertInstanceOf(
            $expectedClass,
            $this->callMethod(
                $sut,
                'applyMakeUniqueHandler',
                [$configuration, $handler]
            )
        );
    }

    public static function applyMakeUniqueHandlerDataProvider(): Generator
    {
        yield 'empty config' => [[], StreamHandler::class];
        yield 'simple deduplicate' => [[LoggerFactory::SPECIAL_HANDLERS_MAKE_UNIQUE], DeduplicationHandler::class];
        yield 'advanced deduplicate' => [
            [LoggerFactory::SPECIAL_HANDLERS_MAKE_UNIQUE   => [LoggerFactory::MAKEUNIQUE_OPTION_TIME => 30]],
            DeduplicationHandler::class,
        ];
    }
}