<?php

namespace Tests\Feature\Configurations;

use App\Livewire\Configurations\Manager\Index as ConfiguracionesDelManager;
use App\Models\Auth\User;
use App\Support\LimiteDeSubida;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * Los cuatro topes de subida se pueden ver sin entrar por SSH (PRODSECU-156).
 *
 * **Por qué hay una pantalla y no basta con el mensaje del formulario.** El formulario dice
 * su tope, y ya está bien que lo diga; pero cuando una subida falla, lo que hace falta es
 * ver **las cuatro capas juntas**, porque la que corta casi nunca es la del formulario.
 *
 * Y hay un test aquí que parece tonto y es el que más vale:
 * `test_el_diagnostico_esta_enganchado_a_la_pantalla`. `LimiteDeSubida::diagnostico()` se
 * escribió y **no lo llamaba nadie** —código sin punto de entrada, el patrón que este
 * release lleva encontrando cinco veces: MGR-039, MGR-045, MGR-060, MGR-062, MGR-070—. Un
 * método de diagnóstico que no está en ninguna pantalla no diagnostica nada.
 */
class LimitesDeSubidaVisiblesTest extends TestCase
{
    use RefreshDatabase;

    protected function tearDown(): void
    {
        LimiteDeSubida::dejarDeFingir();

        parent::tearDown();
    }

    private function quienConfigura(): User
    {
        $rol = Role::firstOrCreate(['name' => 'RolDeConfiguracion', 'guard_name' => 'web']);
        $rol->givePermissionTo(Permission::firstOrCreate(
            ['name' => 'admin.configurations.manager.index', 'guard_name' => 'web'],
            ['model' => 'configurations', 'description' => 'Configuraciones del Manager']
        ));

        $user = User::factory()->create();
        $user->assignRole($rol);
        $this->actingAs($user);

        Cache::flush();

        return $user;
    }

    public function test_el_diagnostico_esta_enganchado_a_la_pantalla(): void
    {
        // **El test que evita el método muerto.** Si alguien quita el bloque de la vista o
        // la clave del `render()`, esto salta.
        $this->quienConfigura();

        $datos = Livewire::test(ConfiguracionesDelManager::class)->viewData('subidas');

        $this->assertIsArray($datos);
        $this->assertSame(LimiteDeSubida::diagnostico(), $datos);
    }

    public function test_se_ven_las_cuatro_capas_con_su_nombre(): void
    {
        // Los nombres exactos importan: son los que hay que buscar en el servidor.
        $this->quienConfigura();

        Livewire::test(ConfiguracionesDelManager::class)
            ->assertSee('Límite de subida de archivos')
            ->assertSee('Validación del panel')
            ->assertSee('upload_max_filesize')
            ->assertSee('post_max_size')
            ->assertSee('client_max_body_size');
    }

    public function test_la_capa_de_nginx_se_pinta_con_una_interrogacion(): void
    {
        // **`?` es la respuesta correcta**, no un hueco: PHP no puede leer
        // `client_max_body_size` porque cuando el servidor web corta, PHP no se ejecuta.
        // Poner un número inventado sería peor —misma lección que MGR-076 y MGR-017—.
        $this->quienConfigura();

        $componente = Livewire::test(ConfiguracionesDelManager::class);

        $this->assertNull($componente->viewData('subidas')['client_max_body_size_kb']);
        $componente->assertSee('NO se puede leer desde aquí');
    }

    public function test_dice_el_tope_efectivo_y_no_uno_escrito_a_mano(): void
    {
        $this->quienConfigura();

        LimiteDeSubida::fingirIni(['upload_max_filesize' => '2M', 'post_max_size' => '2G']);

        Livewire::test(ConfiguracionesDelManager::class)
            ->assertSee('2 MB')
            ->assertDontSee('Hoy se puede subir como máximo <strong>5 MB</strong>', escape: false);
    }

    public function test_avisa_cuando_el_servidor_recorta_el_tope(): void
    {
        // Es la frase que dice a quién hay que pedirle el cambio.
        $this->quienConfigura();

        LimiteDeSubida::fingirIni(['upload_max_filesize' => '1M', 'post_max_size' => '1M']);

        Livewire::test(ConfiguracionesDelManager::class)
            ->assertSee('El servidor recorta el tope')
            ->assertSee('está por debajo de lo que pide el panel');
    }

    public function test_sin_recorte_explica_el_413_silencioso(): void
    {
        // Cuando todo está bien, lo útil es otra cosa: qué mirar si una subida falla **sin
        // dar ningún mensaje**, que es el síntoma exacto del ticket.
        $this->quienConfigura();

        LimiteDeSubida::fingirIni(['upload_max_filesize' => '2G', 'post_max_size' => '2G']);

        Livewire::test(ConfiguracionesDelManager::class)
            ->assertDontSee('El servidor recorta el tope')
            ->assertSee('sin dar ningún mensaje')
            ->assertSee('413');
    }

    public function test_tambien_se_dice_el_tope_de_los_zip(): void
    {
        // Los ZIP de SCSS-CDN son otro orden de magnitud y tienen su propio tope.
        $this->quienConfigura();

        LimiteDeSubida::fingirIni(['upload_max_filesize' => '2G', 'post_max_size' => '2G']);

        Livewire::test(ConfiguracionesDelManager::class)->assertSee('50 MB');
    }

    public function test_sin_permiso_no_se_ve(): void
    {
        // El bloque enseña configuración del servidor: no es para cualquiera.
        $rol = Role::firstOrCreate(['name' => 'RolSinConfiguracion', 'guard_name' => 'web']);
        $user = User::factory()->create();
        $user->assignRole($rol);
        $this->actingAs($user);
        Cache::flush();

        $this->get(route('configurations.manager.index'))->assertForbidden();
    }
}
