<?php

declare(strict_types=1);

namespace Tests\Unit\Support;

use App\Support\Utf8Cleaner;
use PHPUnit\Framework\TestCase;

class Utf8CleanerTest extends TestCase
{
    /** @test */
    public function returns_non_string_values_as_is(): void
    {
        $this->assertSame(123, Utf8Cleaner::clean(123));
        $this->assertSame(12.3, Utf8Cleaner::clean(12.3));
        $this->assertSame(true, Utf8Cleaner::clean(true));
        $this->assertSame(false, Utf8Cleaner::clean(false));
        $this->assertNull(Utf8Cleaner::clean(null));
    }

    /** @test */
    public function leaves_valid_utf8_strings_unchanged(): void
    {
        $value = 'Привет, мир! 😀';

        $this->assertSame($value, Utf8Cleaner::clean($value));
    }

    /** @test */
    public function cleans_strings_with_invalid_utf8_bytes(): void
    {
        // Строка с заведомо некорректной UTF-8 последовательностью.
        $invalid = "\xF0\x28\x8C\x28";

        $cleaned = Utf8Cleaner::clean($invalid);

        $this->assertIsString($cleaned);
        $this->assertNotSame($invalid, $cleaned);

        $json = json_encode($cleaned);
        $this->assertNotFalse($json, 'Resulting string must be valid UTF-8 for json_encode');
    }

    /** @test */
    public function cleans_nested_arrays_recursively(): void
    {
        $invalid = "\xF0\x28\x8C\x28";

        $data = [
            'foo' => 'bar',
            'nested' => [
                'value' => $invalid,
            ],
        ];

        $cleaned = Utf8Cleaner::clean($data);

        $this->assertIsArray($cleaned);
        $this->assertSame('bar', $cleaned['foo']);
        $this->assertIsString($cleaned['nested']['value']);
        $this->assertNotSame($invalid, $cleaned['nested']['value']);

        $json = json_encode($cleaned);
        $this->assertNotFalse($json);
    }

    /** @test */
    public function cleans_objects_recursively(): void
    {
        $invalid = "\xF0\x28\x8C\x28";

        $object = new class {
            public string $name = 'test';
            public array $meta = [];
        };

        $object->meta['invalid'] = $invalid;

        $cleaned = Utf8Cleaner::clean($object);

        $this->assertSame('test', $cleaned->name);
        $this->assertIsString($cleaned->meta['invalid']);
        $this->assertNotSame($invalid, $cleaned->meta['invalid']);

        $json = json_encode($cleaned);
        $this->assertNotFalse($json);
    }
}

