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

use PHPUnit\Framework\TestCase;
use Domain\Languages\LanguagesRepository;

class LanguagesRepositoryTest extends TestCase
{
    public function testLanguageDetailsReturnsArrayOrNull(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_langs', '*', ['id' => 'pl'])
            ->willReturn(['id' => 'pl', 'name' => 'Polski']);

        $repository = new LanguagesRepository($mockDb);
        $language = $repository->languageDetails('pl');

        $this->assertIsArray($language);
        $this->assertSame('pl', $language['id']);
    }

    public function testLanguagesListReturnsArray(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
            ->willReturn([
                ['id' => 'pl', 'name' => 'Polski', 'status' => 1],
            ]);

        $repository = new LanguagesRepository($mockDb);
        $list = $repository->languagesList(false);

        $this->assertCount(1, $list);
        $this->assertSame('pl', $list[0]['id']);
    }

    public function testSaveLanguageRejectsInvalidLanguageId(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $repository = new LanguagesRepository($mockDb);

        $this->assertNull($repository->saveLanguage('pol', 'Polski', 1, 1, 1));
        $this->assertNull($repository->saveLanguage('p1', 'Polski', 1, 1, 1));
    }

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

        $mockDb->expects($this->once())
            ->method('insert')
            ->with('pp_langs_translations', ['text' => 'Hello'])
            ->willReturn($this->createMock(\PDOStatement::class));

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

        $mockDb->expects($this->exactly(2))
            ->method('update')
            ->withConsecutive(
                ['pp_langs_translations', ['pl' => 'Czesc'], ['id' => 15]],
                ['pp_langs_translations', ['en' => 'Hello'], ['id' => 15]]
            );

        $repository = new LanguagesRepository($mockDb);
        $savedId = $repository->saveTranslation(0, 'Hello', ['pl' => 'Czesc', 'en' => 'Hello']);

        $this->assertSame(15, $savedId);
    }

    public function testDeleteTranslationReturnsBoolean(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('delete')
            ->with('pp_langs_translations', ['id' => 5])
            ->willReturn($this->createMock(\PDOStatement::class));

        $repository = new LanguagesRepository($mockDb);
        $this->assertTrue($repository->deleteTranslation(5));
    }

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

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

        $dataStmt = $this->createMock(\PDOStatement::class);
        $dataStmt->expects($this->once())
            ->method('fetchAll')
            ->willReturn([
                ['id' => 'pl', 'name' => 'Polski', 'status' => 1, 'start' => 1, 'o' => 1],
            ]);

        $mockDb->expects($this->exactly(2))
            ->method('query')
            ->willReturnOnConsecutiveCalls($countStmt, $dataStmt);

        $repository = new LanguagesRepository($mockDb);
        $result = $repository->listForAdmin(['name' => '', 'status' => '', 'start' => ''], 'o', 'ASC', 1, 15);

        $this->assertSame(1, $result['total']);
        $this->assertCount(1, $result['items']);
        $this->assertSame('pl', $result['items'][0]['id']);
    }

    public function testDefaultLanguageIdReturnsLanguageWithStartFlag(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
            ->willReturn([
                ['id' => 'en', 'start' => 0],
                ['id' => 'pl', 'start' => 1],
            ]);

        $repository = new LanguagesRepository($mockDb);
        $this->assertSame('pl', $repository->defaultLanguageId());
    }

    public function testDefaultLanguageIdFallsBackToFirstLanguageOrPl(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->expects($this->exactly(2))
            ->method('select')
            ->with('pp_langs', '*', ['ORDER' => ['o' => 'ASC']])
            ->willReturnOnConsecutiveCalls(
                [
                    ['id' => 'en', 'start' => 0],
                ],
                []
            );

        $repository = new LanguagesRepository($mockDb);
        $this->assertSame('en', $repository->defaultLanguageId());
        $this->assertSame('pl', $repository->defaultLanguageId());
    }

    // --- Metody frontendowe (z cache Redis) ---

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

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

        $mockDb->expects($this->once())
            ->method('query')
            ->with('SELECT id FROM pp_langs WHERE status = 1 ORDER BY start DESC, o ASC LIMIT 1')
            ->willReturn($mockStmt);

        $repository = new LanguagesRepository($mockDb);
        $langId = $repository->defaultLanguage();

        $this->assertEquals('pl', $langId);
    }

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

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

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

        $repository = new LanguagesRepository($mockDb);
        $langId = $repository->defaultLanguage();

        $this->assertEquals('pl', $langId);
    }

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

        $mockDb->expects($this->once())
            ->method('select')
            ->with(
                'pp_langs',
                ['id', 'name'],
                ['status' => 1, 'ORDER' => ['o' => 'ASC']]
            )
            ->willReturn([
                ['id' => 'pl', 'name' => 'Polski'],
                ['id' => 'en', 'name' => 'English'],
            ]);

        $repository = new LanguagesRepository($mockDb);
        $languages = $repository->activeLanguages();

        $this->assertIsArray($languages);
        $this->assertCount(2, $languages);
        $this->assertEquals('pl', $languages[0]['id']);
        $this->assertEquals('English', $languages[1]['name']);
    }

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

        $mockDb->expects($this->once())
            ->method('select')
            ->willReturn(null);

        $repository = new LanguagesRepository($mockDb);
        $languages = $repository->activeLanguages();

        $this->assertIsArray($languages);
        $this->assertEmpty($languages);
    }

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

        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_langs_translations', ['text', 'pl'])
            ->willReturn([
                ['text' => 'basket', 'pl' => 'Koszyk'],
                ['text' => 'order', 'pl' => 'Zamowienie'],
            ]);

        $repository = new LanguagesRepository($mockDb);
        $translations = $repository->translations('pl');

        $this->assertIsArray($translations);
        $this->assertEquals('pl', $translations['0']);
        $this->assertEquals('Koszyk', $translations['basket']);
        $this->assertEquals('Zamowienie', $translations['order']);
    }

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

        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_langs_translations', ['text', 'pl'])
            ->willReturn([]);

        $repository = new LanguagesRepository($mockDb);
        $translations = $repository->translations();

        $this->assertIsArray($translations);
        $this->assertEquals('pl', $translations['0']);
    }

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

        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_langs_translations', ['text', 'en'])
            ->willReturn([
                ['text' => 'basket', 'en' => 'Cart'],
            ]);

        $repository = new LanguagesRepository($mockDb);
        $translations = $repository->translations('en');

        $this->assertEquals('en', $translations['0']);
        $this->assertEquals('Cart', $translations['basket']);
    }
}
