<?php

/**
 * Questo file è parte di Pongho.
 *
 * @author    Daniele De Nobili
 * @copyright Web Agency Meta Line S.r.l.
 * @package   Application\Admin
 */

namespace Application\Admin\Tests\Widgets;

use Application\Admin\Widgets\WidgetInterface;
use Application\Admin\Widgets\WidgetsCollection;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\DomCrawler\Crawler;
use Traversable;

class WidgetsCollectionTest extends \PHPUnit\Framework\TestCase
{
    public function testCollection(): void
    {
        $coll = new WidgetsCollection();
        $this->assertFalse($coll->has('foo'));
        $this->assertCount(0, $coll->all());

        $widget = $this->getWidgetMock('foo');
        $coll->add($widget);

        $this->assertTrue($coll->has('foo'));
        $this->assertSame($widget, $coll->get('foo'));
        $this->assertCount(1, $coll->all());

        $coll->del('foo');
        $this->assertFalse($coll->has('foo'));
        $this->assertCount(0, $coll->all());
    }

    public function testAddAfter(): void
    {
        $coll = new WidgetsCollection();
        $coll->add($this->getWidgetMock('foo'));
        $coll->add($this->getWidgetMock('baz'));
        $coll->addAfter($this->getWidgetMock('bar'), 'foo');

        $this->assertEquals(['foo', 'bar', 'baz'], array_keys($coll->all()));
    }

    public function testAddAtBeginning(): void
    {
        $coll = new WidgetsCollection();
        $coll->add($this->getWidgetMock('bar'));
        $coll->add($this->getWidgetMock('baz'));
        $coll->addAfter($this->getWidgetMock('foo'));

        $this->assertEquals(['foo', 'bar', 'baz'], array_keys($coll->all()));
    }

    public function testNotFoundException(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        $coll = new WidgetsCollection();
        $coll->get('foo');
    }

    public function testTraversable(): void
    {
        $coll = new WidgetsCollection();
        $this->assertInstanceOf(Traversable::class, $coll);

        $coll->add($this->getWidgetMock('foo'));
        $coll->add($this->getWidgetMock('bar'));

        $counter = 0;
        foreach ($coll as $panel) {
            $this->assertInstanceOf(WidgetInterface::class, $panel);
            $counter++;
        }

        $this->assertEquals(2, $counter);
    }

    public function testClear(): void
    {
        $coll = new WidgetsCollection();
        $coll->add($this->getWidgetMock('foo'));
        $coll->add($this->getWidgetMock('bar'));
        $coll->add($this->getWidgetMock('baz'));
        $this->assertCount(3, $coll->all());

        $coll->clear();
        $this->assertCount(0, $coll->all());
    }

    public function testRender(): void
    {
        $coll = new WidgetsCollection();

        $coll->add($this->getWidgetForRenderMock('foo-key', 'Foo Title', 'Foo Content', 2));
        $coll->add($this->getWidgetForRenderMock('bar-key', 'Bar Title', 'Bar Content', 1));
        $coll->add($this->getWidgetForRenderMock('baz-key', 'Baz Title', 'Baz Content', 1));

        $crawler = new Crawler($coll->render());

        $this->assertEquals(3, $crawler->filter('div.widget')->count());
        $this->assertEquals(2, $crawler->filter('div.widget-column1')->count());
        $this->assertEquals(1, $crawler->filter('div.widget-column2')->count());

        $this->assertEquals(3, $crawler->filter('div.widget h3')->count());
        $this->assertEquals(3, $crawler->filter('div.widget div.widget-content')->count());

        $this->assertEquals(1, $crawler->filter('#widget-foo-key')->count());
        $this->assertEquals(1, $crawler->filter('#widget-bar-key')->count());
        $this->assertEquals(1, $crawler->filter('#widget-baz-key')->count());
    }

    /**
     * @param string $key
     */
    private function getWidgetMock($key): WidgetInterface|MockObject
    {
        $widget = $this->createMock(WidgetInterface::class);

        $widget->expects($this->any())->method('getKey')->willReturn($key);

        return $widget;
    }

    /**
     * @param string $key
     * @param string $title
     * @param string $content
     * @param int    $columns
     */
    private function getWidgetForRenderMock($key, $title, $content, $columns): WidgetInterface|MockObject
    {
        $widget = $this->createMock(WidgetInterface::class);

        $widget->expects($this->exactly(2))->method('getKey')->willReturn($key);
        $widget->expects($this->once())->method('getTitle')->willReturn($title);
        $widget->expects($this->once())->method('getContent')->willReturn($content);
        $widget->expects($this->once())->method('getColumns')->willReturn($columns);

        return $widget;
    }
}
