<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Tests\Utils;

use Dealerdirect\Agreements\Exceptions\InvalidTranslationTypeException;
use Dealerdirect\Agreements\Tests\TestCase;
use DealerDirect\Generic\Category\Site;

/**
 * @covers \Dealerdirect\Agreements\Utils\Translator
 *
 * @uses \Dealerdirect\Agreements\Enums\Locale
 * @uses \Dealerdirect\Agreements\Utils\GeneralUtils
 */
final class TranslatorTest extends TestCase
{
    /**
     * @runInSeparateProcess
     */
    public function test_get_instance_should_throw_exception_when_translator_is_not_initialized(): void
    {
        $this->expectException(\LogicException::class);

        \Dealerdirect\Agreements\Utils\Translator::getInstance();
    }

    public function test_get_instance_should_return_instance_when_initialized(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => [],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertSame($translator, \Dealerdirect\Agreements\Utils\Translator::getInstance());
    }

    public function test_translate_should_return_translated_string(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => ['foo' => 'bar'],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertSame('bar', $translator->get('general.foo'));
    }

    /**
     * @covers \Dealerdirect\Agreements\Exceptions\InvalidTranslationTypeException
     */
    public function test_construct_should_throw_exception_when_invalid_translation_key_is_provided(): void
    {
        $this->expectException(InvalidTranslationTypeException::class);

        new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'invalid_key' => [],
            ]
        );
    }

    public function test_can_construct_with_valid_translations(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => [],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertInstanceOf(\Dealerdirect\Agreements\Utils\Translator::class, $translator);
    }

    public function test_get_should_return_translation(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => ['foo' => 'bar'],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertSame('bar', $translator->get('general.foo'));
    }

    public function test_get_should_return_translation_with_replacements(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => ['foo' => 'Hello, {{name}}!'],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertSame('Hello, Benny Blind!', $translator->get('general.foo', ['name' => 'Benny Blind']));
    }

    public function test_get_should_return_translation_with_replacements_and_multiple_placeholders(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => ['foo' => 'Hello, {{name}}! You are {{age}} years old.'],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->assertSame(
            'Hello, Benny Blind! You are 42 years old.',
            $translator->get('general.foo', ['name' => 'Benny Blind', 'age' => 42])
        );
    }

    /**
     * @covers \Dealerdirect\Agreements\Exceptions\InvalidTranslationValueException
     */
    public function test_get_should_throw_exception_when_translation_value_is_not_a_string_with_replacements(): void
    {
        $this->expectException(\Dealerdirect\Agreements\Exceptions\InvalidTranslationValueException::class);

        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => ['foo' => ['Hello, {{name}}!']],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $translator->get('general.foo', ['name' => 'Benny Blind']);
    }

    /**
     * @covers \Dealerdirect\Agreements\Exceptions\TranslationNotFoundException
     */
    public function test_get_should_throw_exception_when_translation_key_is_not_found(): void
    {
        $translator = new \Dealerdirect\Agreements\Utils\Translator(
            \Dealerdirect\Agreements\Enums\Locale::NL_NL,
            [
                'general' => [],
                'options' => [],
                'vehicle' => [],
                'sales_agreement' => [],
                'labels' => [],
            ]
        );

        $this->expectException(\Dealerdirect\Agreements\Exceptions\TranslationNotFoundException::class);

        $translator->get('general.foo');
    }

    public function test_create_should_return_new_instance(): void
    {
        $translator = \Dealerdirect\Agreements\Utils\Translator::create(Site::REF_CAR_NL);

        $this->assertInstanceOf(\Dealerdirect\Agreements\Utils\Translator::class, $translator);
    }

    /**
     * @covers \Dealerdirect\Agreements\Exceptions\FileNotFoundException
     */
    public function test_create_should_throw_exception_when_agreements_file_not_found(): void
    {
        $this->expectException(\Dealerdirect\Agreements\Exceptions\FileNotFoundException::class);

        \Dealerdirect\Agreements\Utils\Translator::create(Site::REF_CAR_NL, '/invalid/path');
    }

    /**
     * @runInSeparateProcess
     *
     * @covers \Dealerdirect\Agreements\Exceptions\FileNotFoundException
     */
    public function test_create_should_throw_exception_when_labels_file_not_found(): void
    {
        $this->expectException(\Dealerdirect\Agreements\Exceptions\FileNotFoundException::class);

        \Dealerdirect\Agreements\Utils\Translator::create(
            Site::REF_CAR_BE_NL,
            $this->getResourcesPath() . '/lang'
        );
    }
}
