<?php

declare(strict_types=1);

namespace LaminasTest\I18n\Translator\Loader;

use Laminas\I18n\Exception\InvalidArgumentException;
use Laminas\I18n\Translator\Loader\Ini as IniLoader;
use Laminas\I18n\Translator\TextDomain;
use LaminasTest\I18n\TestCase;

use function get_include_path;
use function realpath;
use function set_include_path;

use const PATH_SEPARATOR;

class IniTest extends TestCase
{
    private string $testFilesDir;
    private string $originalIncludePath;

    protected function setUp(): void
    {
        parent::setUp();
        $this->testFilesDir        = realpath(__DIR__ . '/../_files');
        $this->originalIncludePath = get_include_path();
        set_include_path($this->testFilesDir . PATH_SEPARATOR . $this->testFilesDir . '/translations.phar');
    }

    protected function tearDown(): void
    {
        set_include_path($this->originalIncludePath);
        parent::tearDown();
    }

    public function testLoaderFailsToLoadMissingFile(): void
    {
        $loader = new IniLoader();
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('Could not find or open file');
        $loader->load('en_EN', 'missing');
    }

    public function testLoaderLoadsEmptyFile(): void
    {
        $loader     = new IniLoader();
        $textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_empty.ini');
        self::assertInstanceOf(TextDomain::class, $textDomain);
    }

    public function testLoaderFailsToLoadNonArray(): void
    {
        $loader = new IniLoader();
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('Each INI row must be an array with message and translation');
        $loader->load('en_EN', $this->testFilesDir . '/failed.ini');
    }

    public function testLoaderFailsToLoadBadSyntax(): void
    {
        $loader = new IniLoader();
        $this->expectException(InvalidArgumentException::class);
        $this->expectExceptionMessage('Each INI row must be an array with message and translation');
        $loader->load('en_EN', $this->testFilesDir . '/failed_syntax.ini');
    }

    public function testLoaderReturnsValidTextDomain(): void
    {
        $loader     = new IniLoader();
        $textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en.ini');

        self::assertEquals('Message 1 (en)', $textDomain['Message 1']);
        self::assertEquals('Message 4 (en)', $textDomain['Message 4']);
    }

    public function testLoaderReturnsValidTextDomainWithFileWithoutPlural(): void
    {
        $loader     = new IniLoader();
        $textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en_without_plural.ini');

        self::assertEquals('Message 1 (en)', $textDomain['Message 1']);
        self::assertEquals('Message 4 (en)', $textDomain['Message 4']);
    }

    public function testLoaderReturnsValidTextDomainWithSimpleSyntax(): void
    {
        $loader     = new IniLoader();
        $textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en_simple_syntax.ini');

        self::assertEquals('Message 1 (en)', $textDomain['Message 1']);
        self::assertEquals('Message 4 (en)', $textDomain['Message 4']);
    }

    public function testLoaderLoadsPluralRules(): void
    {
        $loader     = new IniLoader();
        $textDomain = $loader->load('en_EN', $this->testFilesDir . '/translation_en.ini');

        self::assertEquals(2, $textDomain->getPluralRule()->evaluate(0));
        self::assertEquals(0, $textDomain->getPluralRule()->evaluate(1));
        self::assertEquals(1, $textDomain->getPluralRule()->evaluate(2));
        self::assertEquals(2, $textDomain->getPluralRule()->evaluate(10));
    }

    public function testLoaderLoadsFromIncludePath(): void
    {
        $loader = new IniLoader();
        $loader->setUseIncludePath(true);
        $textDomain = $loader->load('en_EN', 'translation_en.ini');

        self::assertEquals('Message 1 (en)', $textDomain['Message 1']);
        self::assertEquals('Message 4 (en)', $textDomain['Message 4']);
    }

    public function testLoaderLoadsFromPhar(): void
    {
        $loader = new IniLoader();
        $loader->setUseIncludePath(true);
        $textDomain = $loader->load('en_EN', 'phar://' . $this->testFilesDir . '/translations.phar/translation_en.ini');

        self::assertEquals('Message 1 (en)', $textDomain['Message 1']);
        self::assertEquals('Message 4 (en)', $textDomain['Message 4']);
    }
}
