<?php
namespace Tests\Unit\Domain\Banner;

use PHPUnit\Framework\TestCase;
use Domain\Banner\BannerRepository;

class BannerRepositoryTest extends TestCase
{
    /**
     * Test pobierania banera - zwraca dane z tłumaczeniami
     */
    public function testFindReturnsBannerWithTranslations()
    {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_banners', '*', ['id' => 1])
            ->willReturn(['id' => 1, 'name' => 'Baner testowy', 'status' => 1]);

        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_banners_langs', '*', [
                'id_banner' => 1,
                'ORDER' => ['id' => 'ASC'],
            ])
            ->willReturn([
                ['id_lang' => 'pl', 'src' => 'banner.jpg', 'url' => '/promo'],
                ['id_lang' => 'en', 'src' => 'banner-en.jpg', 'url' => '/promo-en'],
            ]);

        $repository = new BannerRepository($mockDb);

        // Act
        $banner = $repository->find(1);

        // Assert
        $this->assertIsArray($banner);
        $this->assertEquals('Baner testowy', $banner['name']);
        $this->assertArrayHasKey('languages', $banner);
        $this->assertCount(2, $banner['languages']);
        $this->assertEquals('banner.jpg', $banner['languages']['pl']['src']);
    }

    /**
     * Test pobierania banera - nie istnieje
     */
    public function testFindReturnsNullWhenNotFound()
    {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->method('get')->willReturn(false);

        $repository = new BannerRepository($mockDb);

        // Act
        $banner = $repository->find(999);

        // Assert
        $this->assertNull($banner);
    }

    /**
     * Test usuwania banera - sukces
     */
    public function testDeleteReturnsTrue()
    {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('delete')
            ->with('pp_banners', ['id' => 5])
            ->willReturn($this->createMock(\PDOStatement::class));

        $repository = new BannerRepository($mockDb);

        // Act
        $result = $repository->delete(5);

        // Assert
        $this->assertTrue($result);
    }

    /**
     * Test zapisywania nowego banera (stary format danych - zachowano kompatybilność)
     */
    public function testSaveInsertsNewBanner()
    {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);

        // insert() wywoływane 2x: raz dla banera, raz dla tłumaczenia
        $mockDb->expects($this->exactly(2))
            ->method('insert');

        $mockDb->expects($this->once())
            ->method('id')
            ->willReturn(10);

        // get() for checking existing translations - returns false (no existing)
        $mockDb->method('get')->willReturn(false);

        $repository = new BannerRepository($mockDb);

        // Act - nowy format z FormRequestHandler (przetworzone dane)
        $result = $repository->save([
            'name' => 'Nowy baner',
            'status' => 1,  // już przetworzone na int
            'date_start' => null,
            'date_end' => null,
            'home_page' => 1,  // już przetworzone na int
            'translations' => [
                1 => [  // id języka jako klucz
                    'src' => 'banner.jpg',
                    'url' => '/promo',
                    'html' => '',
                    'text' => 'Tekst',
                ],
            ],
        ]);

        // Assert
        $this->assertEquals(10, $result);
    }

    /**
     * Test zapisywania banera ze starym formatem danych (backward compatibility)
     */
    public function testSaveWithLegacyFormat()
    {
        // Arrange
        $mockDb = $this->createMock(\medoo::class);

        // insert() wywoływane 2x: raz dla banera, raz dla tłumaczenia
        $mockDb->expects($this->exactly(2))
            ->method('insert');

        $mockDb->expects($this->once())
            ->method('id')
            ->willReturn(11);

        // get() for checking existing translations - returns false (no existing)
        $mockDb->method('get')->willReturn(false);

        $repository = new BannerRepository($mockDb);

        // Act - stary format (dla kompatybilności wstecznej)
        $result = $repository->save([
            'name' => 'Baner legacy',
            'status' => 'on',
            'date_start' => '',
            'date_end' => '',
            'home_page' => 'on',
            'src' => ['pl' => 'banner.jpg'],
            'url' => ['pl' => '/promo'],
            'html' => ['pl' => ''],
            'text' => ['pl' => 'Tekst'],
        ]);

        // Assert
        $this->assertEquals(11, $result);
    }

    /**
     * Test zapisu istniejacego banera - aktualizacja tlumaczen po id_banner + id_lang
     */
    public function testSaveUpdatesExistingTranslationsByBannerAndLang(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $mockDb->expects($this->exactly(2))
            ->method('update')
            ->withConsecutive(
                [
                    'pp_banners',
                    $this->arrayHasKey('name'),
                    ['id' => 5],
                ],
                [
                    'pp_banners_langs',
                    $this->callback(function (array $data): bool {
                        return $data['id_banner'] === 5
                            && $data['id_lang'] === 'pl'
                            && $data['src'] === 'banner-new.jpg';
                    }),
                    ['AND' => ['id_banner' => 5, 'id_lang' => 'pl']],
                ]
            );

        $mockDb->expects($this->once())
            ->method('count')
            ->with('pp_banners_langs', ['AND' => ['id_banner' => 5, 'id_lang' => 'pl']])
            ->willReturn(2);

        $mockDb->expects($this->never())
            ->method('insert');

        $repository = new BannerRepository($mockDb);

        $result = $repository->save([
            'id' => 5,
            'name' => 'Baner update',
            'status' => 1,
            'date_start' => null,
            'date_end' => null,
            'home_page' => 0,
            'translations' => [
                'pl' => [
                    'src' => 'banner-new.jpg',
                    'url' => '/promo-new',
                    'html' => '<b>promo</b>',
                    'text' => 'Nowa tresc',
                ],
            ],
        ]);

        $this->assertSame(5, $result);
    }

    public function testListForAdminIncludesThumbnailSrc(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $countStmt = $this->createMock(\PDOStatement::class);
        $countStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([[2]]);

        $itemsStmt = $this->createMock(\PDOStatement::class);
        $itemsStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([
                [
                    'id' => 10,
                    'name' => 'Baner A',
                    'status' => 1,
                    'home_page' => 0,
                    'date_start' => null,
                    'date_end' => null,
                ],
                [
                    'id' => 11,
                    'name' => 'Baner B',
                    'status' => 1,
                    'home_page' => 1,
                    'date_start' => null,
                    'date_end' => null,
                ],
            ]);

        $thumbsStmt = $this->createMock(\PDOStatement::class);
        $thumbsStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([
                ['id_banner' => 10, 'src' => '/uploads/banner-a.jpg'],
            ]);

        $mockDb->expects($this->exactly(3))
            ->method('query')
            ->willReturnOnConsecutiveCalls($countStmt, $itemsStmt, $thumbsStmt);

        $repository = new BannerRepository($mockDb);

        $result = $repository->listForAdmin([], 'name', 'ASC', 1, 15);

        $this->assertSame(2, $result['total']);
        $this->assertCount(2, $result['items']);
        $this->assertSame('/uploads/banner-a.jpg', $result['items'][0]['thumbnail_src']);
        $this->assertSame('', $result['items'][1]['thumbnail_src']);
    }

    // ─── Frontend methods ───────────────────────────────────────────

    /**
     * Test banners() — cache miss, zwraca aktywne banery z plaskim formatem languages
     */
    public function testBannersReturnsActiveBannersWithFlatLanguages(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $queryStmt = $this->createMock(\PDOStatement::class);
        $queryStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([
                ['id' => 1, 'name' => 'Baner A'],
                ['id' => 2, 'name' => 'Baner B'],
            ]);

        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn($queryStmt);

        $mockDb->expects($this->exactly(2))
            ->method('get')
            ->with('pp_banners_langs', '*', $this->anything())
            ->willReturnOnConsecutiveCalls(
                ['id_banner' => 1, 'id_lang' => 'pl', 'src' => 'a.jpg', 'url' => '/a', 'html' => '', 'text' => ''],
                ['id_banner' => 2, 'id_lang' => 'pl', 'src' => 'b.jpg', 'url' => '/b', 'html' => '', 'text' => '']
            );

        $repo = new BannerRepository($mockDb);
        $result = $repo->banners('pl');

        $this->assertIsArray($result);
        $this->assertCount(2, $result);
        // Format plaski — $banner['languages']['src'], nie $banner['languages']['pl']['src']
        $this->assertSame('a.jpg', $result[0]['languages']['src']);
        $this->assertSame('b.jpg', $result[1]['languages']['src']);
    }

    /**
     * Test banners() — brak wynikow zwraca null
     */
    public function testBannersReturnsNullWhenNoBanners(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $queryStmt = $this->createMock(\PDOStatement::class);
        $queryStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([]);

        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn($queryStmt);

        $repo = new BannerRepository($mockDb);
        $result = $repo->banners('pl');

        $this->assertNull($result);
    }

    /**
     * Test mainBanner() — cache miss, zwraca baner z plaskim formatem languages
     */
    public function testMainBannerReturnsActiveBannerWithFlatLanguages(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $queryStmt = $this->createMock(\PDOStatement::class);
        $queryStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([
                ['id' => 5, 'name' => 'Main Banner', 'status' => 1, 'home_page' => 1],
            ]);

        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn($queryStmt);

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_banners_langs', '*', ['AND' => ['id_banner' => 5, 'id_lang' => 'pl']])
            ->willReturn(['id_banner' => 5, 'id_lang' => 'pl', 'src' => 'main.jpg', 'url' => '/main', 'html' => '', 'text' => '']);

        $repo = new BannerRepository($mockDb);
        $result = $repo->mainBanner('pl');

        $this->assertIsArray($result);
        $this->assertSame(5, (int)$result['id']);
        $this->assertSame('main.jpg', $result['languages']['src']);
        $this->assertSame('/main', $result['languages']['url']);
    }

    /**
     * Test mainBanner() — brak wynikow zwraca null
     */
    public function testMainBannerReturnsNullWhenNoBanner(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $queryStmt = $this->createMock(\PDOStatement::class);
        $queryStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([]);

        $mockDb->expects($this->once())
            ->method('query')
            ->willReturn($queryStmt);

        $repo = new BannerRepository($mockDb);
        $result = $repo->mainBanner('pl');

        $this->assertNull($result);
    }
}
