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

use PHPUnit\Framework\TestCase;
use Domain\Dictionaries\DictionariesRepository;

class DictionariesRepositoryTest extends TestCase
{
    public function testFindReturnsUnitWithTranslations(): void
    {
        $mockDb = $this->createMock(\medoo::class);

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_units', '*', ['id' => 5])
            ->willReturn(['id' => 5]);

        $mockDb->expects($this->once())
            ->method('select')
            ->with('pp_units_langs', '*', [
                'unit_id' => 5,
                'ORDER' => ['lang_id' => 'ASC', 'id' => 'ASC'],
            ])
            ->willReturn([
                ['lang_id' => 1, 'text' => 'kg'],
                ['lang_id' => 2, 'text' => 'kg'],
            ]);

        $repository = new DictionariesRepository($mockDb);
        $unit = $repository->find(5);

        $this->assertIsArray($unit);
        $this->assertEquals(5, $unit['id']);
        $this->assertArrayHasKey('languages', $unit);
        $this->assertEquals('kg', $unit['languages'][1]['text']);
    }

    public function testFindReturnsNullWhenUnitNotFound(): void
    {
        $mockDb = $this->createMock(\medoo::class);
        $mockDb->method('get')->willReturn(false);

        $repository = new DictionariesRepository($mockDb);
        $this->assertNull($repository->find(999));
    }

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

        // insert: 1x pp_units + 1x pp_units_langs
        $mockDb->expects($this->exactly(2))
            ->method('insert');

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

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_units_langs', 'id', [
                'AND' => [
                    'unit_id' => 12,
                    'lang_id' => 'pl',
                ],
            ])
            ->willReturn(false);

        $repository = new DictionariesRepository($mockDb);

        $savedId = $repository->save([
            'translations' => [
                'pl' => ['text' => 'szt.'],
            ],
        ]);

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

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

        $mockDb->expects($this->exactly(2))
            ->method('delete')
            ->withConsecutive(
                ['pp_units_langs', ['unit_id' => 7]],
                ['pp_units', ['id' => 7]]
            )
            ->willReturnOnConsecutiveCalls(
                $this->createMock(\PDOStatement::class),
                $this->createMock(\PDOStatement::class)
            );

        $repository = new DictionariesRepository($mockDb);
        $this->assertTrue($repository->delete(7));
    }

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

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_units_langs', 'text', [
                'AND' => [
                    'unit_id' => 2,
                    'lang_id' => 1,
                ],
            ])
            ->willReturn('kg');

        $repository = new DictionariesRepository($mockDb);
        $this->assertSame('kg', $repository->getUnitNameById(2, 1));
    }

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

        $mockDb->expects($this->once())
            ->method('get')
            ->with('pp_units_langs', 'text', [
                'AND' => [
                    'unit_id' => 2,
                    'lang_id' => 'pl',
                ],
            ])
            ->willReturn('kg');

        $repository = new DictionariesRepository($mockDb);
        $this->assertSame('kg', $repository->getUnitNameById(2, 'pl'));
    }

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

        $stmt = $this->createMock(\PDOStatement::class);
        $stmt->expects($this->once())
            ->method('fetchAll')
            ->with(\PDO::FETCH_ASSOC)
            ->willReturn([
                ['id' => 3, 'text' => 'kg'],
                ['id' => 4, 'text' => 'l'],
            ]);

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

        $repository = new DictionariesRepository($mockDb);
        $units = $repository->allUnits();

        $this->assertArrayHasKey(3, $units);
        $this->assertSame('kg', $units[3]['text']);
        $this->assertArrayHasKey(4, $units);
    }
}
