<?php

namespace Tests\Feature\Features;

use App\Livewire\Configurations\Environments\Edit as TipoDeEntornoEdit;
use App\Livewire\Features\Create as FeatureCreate;
use App\Models\Auth\User;
use App\Models\Environments\Type;
use App\Models\Features\Feature;
use App\Models\Features\FeatureVersion;
use App\Models\Products\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Tests\TestCase;

/**
 * El SVG no se admite en la subida de imágenes del editor: es XML y puede llevar
 * <script>, y estos ficheros se sirven desde el MISMO origen que el panel, así que
 * abrir su URL ejecutaría el script con la sesión de quien lo abra.
 * Ver known-issues MGR-020.
 */
class ImageUploadTest extends TestCase
{
    use RefreshDatabase;

    private function actingAsAutor(): User
    {
        $user = User::factory()->create();

        // La tabla `permissions` de este proyecto tiene `model` NOT NULL.
        Permission::firstOrCreate(
            ['name' => 'admin.features.create', 'guard_name' => 'web'],
            ['model' => 'features', 'description' => 'Funcionalidades: Crear']
        );

        $user->givePermissionTo('admin.features.create');
        $this->actingAs($user);

        return $user;
    }

    public function test_no_se_puede_subir_un_svg(): void
    {
        Storage::fake('public');
        $this->actingAsAutor();

        $svg = UploadedFile::fake()->createWithContent(
            'malicioso.svg',
            '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>'
        );

        $respuesta = $this->post('/api/features/upload-image', [
            'image' => $svg,
            'product_id' => null,
            'feature_version_id' => null,
        ]);

        $respuesta->assertStatus(400)
            ->assertJsonPath('error', 1);

        $this->assertStringContainsString('SVG', $respuesta->json('msg'));

        Storage::disk('public')->assertDirectoryEmpty('features');
    }

    public function test_si_se_puede_subir_un_png(): void
    {
        Storage::fake('public');
        $this->actingAsAutor();

        $respuesta = $this->post('/api/features/upload-image', [
            'image' => UploadedFile::fake()->image('captura.png', 400, 300),
            'product_id' => null,
            'feature_version_id' => 1,
        ]);

        // No importa la ruta exacta, sino que la validación de formato lo acepte:
        // el error de formato devuelve 400 con error=1.
        $this->assertNotSame(
            'Formato no admitido',
            substr((string) $respuesta->json('msg'), 0, 20),
            'El PNG no debería rechazarse por formato.'
        );
    }

    public function test_el_error_interno_no_filtra_el_mensaje_de_la_excepcion(): void
    {
        // El catch del controlador no debe devolver $e->getMessage(): filtraría rutas
        // del servidor o estructura de tablas. Se comprueba sobre el código, porque
        // provocar la excepción real exigiría romper el disco a propósito.
        $codigo = file_get_contents(app_path('Http/Controllers/Features/ImageUploadController.php'));

        $this->assertStringNotContainsString('$e->getMessage()', $codigo);
        $this->assertStringContainsString('report($e)', $codigo);
    }
    /**
     * **El barrido, que es lo que faltaba.** El fix de agosto quitó el `svg` de la subida
     * del editor y dejó las otras cuatro puertas: la miniatura y la cabecera de una
     * funcionalidad —al crear y al editar— y la imagen de un tipo de entorno. Todas
     * guardan en el mismo disco `public` y devuelven una URL del propio dominio, así que
     * eran exactamente la misma vía por otro sitio.
     *
     * Se comprueba sobre el código y no caso por caso a propósito: lo que hay que impedir
     * es que **vuelva a aparecer** en una regla nueva.
     */
    public function test_ninguna_validacion_de_subida_admite_svg(): void
    {
        $culpables = [];

        $ficheros = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator(app_path())
        );

        foreach ($ficheros as $fichero) {
            if ($fichero->getExtension() !== 'php') {
                continue;
            }

            foreach (file($fichero->getPathname()) as $n => $linea) {
                if (preg_match('/mimes:[a-z0-9,]*\bsvg\b/i', $linea)) {
                    $culpables[] = str_replace(app_path(), 'app', $fichero->getPathname()) . ':' . ($n + 1);
                }
            }
        }

        $this->assertSame(
            [],
            $culpables,
            "Hay una validación de subida que admite SVG:\n  " . implode("\n  ", $culpables)
        );
    }

    public function test_la_miniatura_de_una_funcionalidad_rechaza_un_svg(): void
    {
        Storage::fake('public');
        $this->actingAsAutor();

        $producto = Product::create([
            'name' => 'Producto con imágenes',
            'slug' => 'conimagenes',
            'actived' => true,
        ]);

        $version = FeatureVersion::create([
            'product_id' => $producto->id,
            'version' => '2026010100',
            'description' => 'Versión de prueba',
        ]);

        $svg = UploadedFile::fake()->createWithContent(
            'logo.svg',
            '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>'
        );

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->set('title', 'Una funcionalidad')
            ->set('thumbnail_image', $svg)
            ->call('save')
            ->assertHasErrors(['thumbnail_image' => 'mimes']);

        $this->assertSame(0, Feature::count());
    }

    public function test_la_imagen_de_un_tipo_de_entorno_rechaza_un_svg(): void
    {
        // **Los cuatro tipos que hay hoy tienen icono SVG**, y siguen funcionando: son
        // ficheros estáticos del repositorio (`images_static/`), no subidas. Lo que se
        // cierra es la puerta de subir uno nuevo.
        Storage::fake('public');

        $usuario = User::factory()->create();

        Permission::firstOrCreate(
            ['name' => 'admin.configurations.environments-types.edit', 'guard_name' => 'web'],
            ['model' => 'configurations', 'description' => 'Configuraciones: Editar tipo de entorno']
        );

        $usuario->givePermissionTo('admin.configurations.environments-types.edit');
        $this->actingAs($usuario);

        $tipo = Type::create([
            'name' => 'Un tipo nuevo',
            'shortname' => 'tiponuevo',
            'description' => 'Para la prueba',
        ]);

        $svg = UploadedFile::fake()->createWithContent(
            'icono.svg',
            '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>'
        );

        Livewire::test(TipoDeEntornoEdit::class, ['type' => $tipo])
            ->set('image', $svg)
            ->call('update')
            ->assertHasErrors(['image' => 'mimes']);
    }
}