<?php

namespace App\tests\Unit\Service\File\Utils;

use App\Entity\Core\File;
use App\Service\File\Utils\FileUtils;
use App\Tests\Unit\TestToolsTrait;
use Liip\ImagineBundle\Imagine\Data\DataManager;
use Liip\ImagineBundle\Imagine\Filter\FilterManager;
use Liip\ImagineBundle\Model\Binary;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class ImageUtilsTest extends TestCase
{
    use TestToolsTrait;

    private MockObject | DataManager $dataManager;
    private MockObject | FilterManager $filterManager;
    private MockObject | LoggerInterface $logger;

    public function setUp(): void
    {
        $this->dataManager = $this->getMockBuilder(DataManager::class)->disableOriginalConstructor()->getMock();
        $this->filterManager = $this->getMockBuilder(FilterManager::class)->disableOriginalConstructor()->getMock();
        $this->logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
    }

    public function getImageUtilsMockFor(string $methodName) {
        return $this->getMockBuilder(FileUtils::class)
            ->setConstructorArgs([$this->dataManager, $this->filterManager, $this->logger])
            ->setMethodsExcept([$methodName])
            ->getMock();
    }

    /**
     * @return void
     * @throws \ReflectionException
     *@see FileUtils::getCroppingConfig()
     */
    public function testGetCroppingConfig(): void {
        $imageUtils = $this->getImageUtilsMockFor('getCroppingConfig');

        $config = '{"width": 100, "height": 100, "x": 10, "y": 10}';
        $result =[
            'filters' => [
                'crop' => [
                    'size' => [100, 100],
                    'start' => [10, 10]
                ]
            ]
        ];

        $this->assertEquals($result, $this->invokeMethod($imageUtils, 'getCroppingConfig', [$config]));
    }


    /**
     * @return void
     *@see FileUtils::formatImage()
     */
    public function testFormatImageWithoutConfig()
    {
        $file = $this->getMockBuilder(File::class)->getMock();
        $file->method('getPath')->willReturn('example.jpg');
        $file->method('getConfig')->willReturn(null);

        $imageUtils = $this->getImageUtilsMockFor('formatImage');

        $binary = $this->createMock(Binary::class);
        $binary->method('getContent')->willReturn('mocked_binary_data');

        $this->dataManager->expects($this->once())
            ->method('find')
            ->with(FileUtils::FILTER_CROP, $file->getPath())
            ->willReturn($binary);

        $result = $imageUtils->formatImage($file);

        $this->assertEquals('mocked_binary_data', $result);
    }

    /**
     * @return void
     *@see FileUtils::formatImage()
     */
    public function testFormatImageWithConfig()
    {
        $file = $this->getMockBuilder(File::class)->getMock();
        $file->method('getPath')->willReturn('example.jpg');
        $file->method('getConfig')->willReturn('{"width": 100, "height": 100, "x": 10, "y": 10}');
        $config  = [
            'filters' => [
                'crop' => [
                    'size' => [100, 100],
                    'start' => [10, 10]
                ]
            ]
        ];

        $imageUtils = $this->getImageUtilsMockFor('formatImage');

        $binary = $this->createMock(Binary::class);
        $binary->method('getContent')->willReturn('mocked_binary_data');

        $this->dataManager->expects($this->once())
            ->method('find')
            ->with(FileUtils::FILTER_CROP, $file->getPath())
            ->willReturn($binary);

        $this->filterManager->expects($this->once())
            ->method('applyFilter')
            ->with($binary, FileUtils::FILTER_CROP, $config)
            ->willReturn($binary);

        $this->logger->expects($this->never())->method('error');

        $result = $imageUtils->formatImage($file);

        $this->assertEquals('mocked_binary_data', $result);
    }


    /**
     * @return void
     *@see FileUtils::formatImage()
     */
    public function testFormatImageWithErrorConfig()
    {
        $file = $this->getMockBuilder(File::class)->getMock();
        $file->method('getPath')->willReturn('example.jpg');
        $file->method('getConfig')->willReturn('{"hei": 100, "x": 10, "y": 10}');

        $imageUtils = $this->getImageUtilsMockFor('formatImage');

        $binary = $this->createMock(Binary::class);
        $binary->method('getContent')->willReturn('mocked_binary_data');

        $this->dataManager->expects($this->once())
            ->method('find')
            ->with(FileUtils::FILTER_CROP, $file->getPath())
            ->willReturn($binary);

        $this->logger->expects($this->exactly(2))
            ->method('error')
        ;

        $result = $imageUtils->formatImage($file);

        $this->assertEquals('mocked_binary_data', $result);
    }

    /**
     * @return void
     *@see FileUtils::isImage()
     */
    public function testIsImage()
    {
        $file = $this->getMockBuilder(File::class)->getMock();
        $file->method('getMimeType')->willReturn('image/jpeg');

        $imageUtils = $this->getImageUtilsMockFor('isImage');

        $this->assertTrue($imageUtils->isImage($file));
    }

    /**
     * @return void
     * @see FileUtils::isImage()
     */
    public function testIsNotImage()
    {
        $file = $this->getMockBuilder(File::class)->getMock();
        $file->method('getMimeType')->willReturn('application/pdf');

        $imageUtils = $this->getImageUtilsMockFor('isImage');

        $this->assertFalse($imageUtils->isImage($file));
    }
}
