<?php

namespace Tests\Feature\Dashboard;

use App\Livewire\Dashboard\Index as Dashboard;
use App\Models\Auth\User;
use App\Models\Clients\Client;
use App\Models\Environments\Data;
use App\Models\Environments\Environment;
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 cinco sitios más grandes del Dashboard, por tres medidas.
 *
 * **La pregunta que no tenía respuesta en ningún sitio**: «¿cuáles son nuestros clientes
 * gordos?». El dato llegaba cada día en la telemetría de cada Moodle y solo se podía ver
 * entrando entorno por entorno.
 *
 * Lo que se fija aquí:
 *
 * 1. Que sean **tres listas y no una**: un campus con muchos usuarios y pocos cursos y otro
 *    con muchos cursos y pocas matrículas no se ordenan igual, y juntarlos obligaría a
 *    inventarse una fórmula que pondere.
 * 2. Que **un sitio sin telemetría no cuente como cero**. No sabemos nada de él, y colarlo
 *    al final de la lista con un 0 sería afirmar algo que nadie ha medido.
 */
class SitiosMasGrandesTest extends TestCase
{
    use RefreshDatabase;

    private function admin(): User
    {
        $rol = Role::firstOrCreate(['name' => 'RolDelDash', 'guard_name' => 'web']);

        foreach (['admin.dashboard.index', 'admin.environments.index'] as $nombre) {
            $rol->givePermissionTo(Permission::firstOrCreate(
                ['name' => $nombre, 'guard_name' => 'web'],
                ['model' => 'dashboard', 'description' => $nombre]
            ));
        }

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

        Cache::flush();

        return $usuario;
    }

    private function sitio(string $nombre, int $usuarios, int $cursos, int $matriculas): Environment
    {
        $cliente = Client::firstOrCreate(['shortname' => 'big'], ['name' => 'Cliente grande', 'actived' => true]);

        $entorno = Environment::create([
            'name' => $nombre,
            'version' => '5.1.1',
            'domain' => 'https://' . str()->slug($nombre) . '.test',
            'env' => 'pro',
            'active' => true,
            'client_id' => $cliente->id,
        ]);

        Data::create([
            'environment_id' => $entorno->id,
            'users' => $usuarios,
            'courses' => $cursos,
            'enrolments' => $matriculas,
        ]);

        return $entorno;
    }

    public function test_cada_medida_tiene_su_propio_orden(): void
    {
        // **Por qué son tres listas y no un ranking.** Estos dos sitios se ordenan al revés
        // según lo que se mire: uno es acceso masivo a poco contenido y el otro un catálogo
        // grande con poca gente. Un número único que los mezclara no diría nada de ninguno.
        $this->admin();

        $this->sitio('Campus masivo', usuarios: 5000, cursos: 10, matriculas: 8000);
        $this->sitio('Catálogo enorme', usuarios: 200, cursos: 900, matriculas: 400);

        $listas = Livewire::test(Dashboard::class)->viewData('masGrandes');

        $this->assertSame('Campus masivo', $listas['users']['filas'][0]['nombre']);
        $this->assertSame('Catálogo enorme', $listas['courses']['filas'][0]['nombre']);
        $this->assertSame('Campus masivo', $listas['enrolments']['filas'][0]['nombre']);
    }

    public function test_solo_entran_cinco(): void
    {
        $this->admin();

        foreach (range(1, 7) as $i) {
            $this->sitio('Sitio ' . $i, usuarios: $i * 100, cursos: $i, matriculas: $i * 10);
        }

        $listas = Livewire::test(Dashboard::class)->viewData('masGrandes');

        $this->assertCount(5, $listas['users']['filas']);
        // El mayor primero: es un ranking, no una lista.
        $this->assertSame('Sitio 7', $listas['users']['filas'][0]['nombre']);
    }

    public function test_un_sitio_sin_telemetria_no_cuenta_como_cero(): void
    {
        // **No sabemos nada de él**, y eso no es lo mismo que saber que tiene cero usuarios.
        // Colarlo al final de la lista con un 0 sería afirmar algo que nadie ha medido.
        $this->admin();

        $this->sitio('Con datos', usuarios: 50, cursos: 5, matriculas: 80);

        Environment::create([
            'name' => 'Callado',
            'version' => '5.1.1',
            'domain' => 'https://callado.test',
            'env' => 'pro',
            'active' => true,
        ]);

        $nombres = collect(Livewire::test(Dashboard::class)->viewData('masGrandes')['users']['filas'])
            ->pluck('nombre')
            ->all();

        $this->assertSame(['Con datos'], $nombres);
    }

    public function test_un_cero_tampoco_entra(): void
    {
        // Un sitio que manda telemetría y dice 0 cursos no pinta nada en «los que más
        // cursos tienen»: ocupa una de las cinco plazas para decir que no tiene ninguno.
        $this->admin();

        $this->sitio('Sin cursos', usuarios: 300, cursos: 0, matriculas: 0);

        $listas = Livewire::test(Dashboard::class)->viewData('masGrandes');

        $this->assertCount(1, $listas['users']['filas']);
        $this->assertSame([], $listas['courses']['filas']);
    }

    public function test_se_identifica_por_el_dominio_y_sin_el_esquema(): void
    {
        // **El dominio y no el nombre**, como pide el diseño: es lo que identifica un sitio
        // de un vistazo y lo que llega escrito en una incidencia. Sin el `https://`, que en
        // una lista estrecha son ocho caracteres que no distinguen nada.
        $this->admin();

        $this->sitio('Campus del cliente', usuarios: 500, cursos: 20, matriculas: 900);

        $fila = Livewire::test(Dashboard::class)->viewData('masGrandes')['users']['filas'][0];

        $this->assertSame('campus-del-cliente.test', $fila['dominio']);
        // El nombre y el cliente no se pierden: van al `title` de la fila.
        $this->assertSame('Campus del cliente', $fila['nombre']);
        $this->assertSame('Cliente grande', $fila['cliente']);
    }

    public function test_sin_permiso_de_entornos_no_se_calcula(): void
    {
        // Enlaza a la ficha de cada entorno y dice el nombre de los clientes: quien no puede
        // ver el listado tampoco debería verlo aquí de rebote.
        $rol = Role::firstOrCreate(['name' => 'SoloDash', 'guard_name' => 'web']);
        $rol->givePermissionTo(Permission::firstOrCreate(
            ['name' => 'admin.dashboard.index', 'guard_name' => 'web'],
            ['model' => 'dashboard', 'description' => 'dash']
        ));

        $usuario = User::factory()->create();
        $usuario->assignRole($rol);
        $this->actingAs($usuario);
        Cache::flush();

        $this->sitio('Con datos', usuarios: 50, cursos: 5, matriculas: 80);

        $this->assertNull(Livewire::test(Dashboard::class)->viewData('masGrandes'));
    }
}
