<?php

namespace Tests\Feature\Products;

use App\Livewire\Features\Create as FeatureCreate;
use App\Livewire\Resources\Create as ResourceCreate;
use App\Livewire\Tutorials\Create as TutorialCreate;
use App\Models\Auth\User;
use App\Models\Features\Feature;
use App\Models\Features\FeatureVersion;
use App\Models\Products\Product;
use App\Models\Resources\Resource;
use App\Models\Resources\ResourceVersion;
use App\Models\Tutorials\Tutorial;
use App\Models\Tutorials\TutorialVersion;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * El campo «Orden» de un elemento nuevo sale con el número que le toca.
 *
 * **Lo que arregla.** Salía vacío y decía «(opcional)», así que se dejaba en blanco casi
 * siempre: es un número que no significa nada mientras escribes una funcionalidad. El
 * elemento se guardaba con `sort_order` a null, los nulos van al final y entre ellos se
 * ordenan por fecha de creación — o sea, por nada que nadie haya decidido. Con dos o tres
 * elementos así, las flechas de subir y bajar dejan de hacer lo que parece y **la API los
 * sirve en ese orden accidental**.
 */
class OrdenPorDefectoTest extends TestCase
{
    use RefreshDatabase;

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

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

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

        return $usuario;
    }

    private function producto(): Product
    {
        return Product::create(['name' => 'Tema orden', 'slug' => 'theme_ord', 'shortname' => 'ord']);
    }

    private function versionDeFeatures(Product $producto): FeatureVersion
    {
        return FeatureVersion::create([
            'product_id' => $producto->id,
            'version' => '2026010100',
            'status' => 'active',
            'created_by' => auth()->id(),
        ]);
    }

    private function feature(FeatureVersion $version, string $titulo, ?int $orden): Feature
    {
        return Feature::create([
            'feature_version_id' => $version->id,
            'title' => $titulo,
            'sort_order' => $orden,
            'status' => 'published',
            'created_by' => auth()->id(),
        ]);
    }

    public function test_en_una_version_vacia_el_primero_es_el_uno(): void
    {
        $this->admin();
        $producto = $this->producto();
        $version = $this->versionDeFeatures($producto);

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->assertSet('sort_order', 1);
    }

    public function test_con_tres_ordenados_el_siguiente_es_el_cuatro(): void
    {
        $this->admin();
        $producto = $this->producto();
        $version = $this->versionDeFeatures($producto);

        foreach ([1, 2, 3] as $orden) {
            $this->feature($version, 'F' . $orden, $orden);
        }

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->assertSet('sort_order', 4);
    }

    public function test_si_los_que_hay_no_tienen_orden_se_cuenta_cuantos_son(): void
    {
        // Es el caso real de hoy: casi todos los elementos cargados tienen el orden a null
        // porque el campo salía vacío. `max(sort_order)` sería null, y el único número
        // honesto es cuántos hay.
        $this->admin();
        $producto = $this->producto();
        $version = $this->versionDeFeatures($producto);

        foreach (['A', 'B'] as $titulo) {
            $this->feature($version, $titulo, null);
        }

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->assertSet('sort_order', 3);
    }

    public function test_con_un_hueco_en_la_numeracion_va_detras_del_mayor(): void
    {
        // Con órdenes 1 y 7, el siguiente es el 8: lo que se pide es que quede el último,
        // no que rellene huecos.
        $this->admin();
        $producto = $this->producto();
        $version = $this->versionDeFeatures($producto);

        $this->feature($version, 'Primera', 1);
        $this->feature($version, 'Séptima', 7);

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->assertSet('sort_order', 8);
    }

    public function test_el_orden_de_otra_version_no_cuenta(): void
    {
        // Cada versión tiene su propia lista: los elementos de la anterior no desplazan a
        // los de esta.
        $this->admin();
        $producto = $this->producto();

        $otra = $this->versionDeFeatures($producto);
        foreach ([1, 2, 3, 4, 5] as $orden) {
            $this->feature($otra, 'Vieja ' . $orden, $orden);
        }

        $version = FeatureVersion::create([
            'product_id' => $producto->id,
            'version' => '2026020100',
            'status' => 'draft',
            'created_by' => auth()->id(),
        ]);

        Livewire::test(FeatureCreate::class, ['product' => $producto, 'featureVersion' => $version])
            ->assertSet('sort_order', 1);
    }

    public function test_los_recursos_y_los_tutoriales_hacen_lo_mismo(): void
    {
        // Los tres tipos con elementos comparten el problema y comparten el arreglo.
        $this->admin();
        $producto = $this->producto();

        $recursos = ResourceVersion::create([
            'product_id' => $producto->id,
            'version' => '2026010100',
            'status' => 'active',
            'created_by' => auth()->id(),
        ]);

        Resource::create([
            'resource_version_id' => $recursos->id,
            'title' => 'Uno',
            'type' => 'external',
            'sort_order' => 1,
            'status' => 'published',
            'created_by' => auth()->id(),
        ]);

        Livewire::test(ResourceCreate::class, ['product' => $producto, 'resourceVersion' => $recursos])
            ->assertSet('sort_order', 2);

        $tutoriales = TutorialVersion::create([
            'product_id' => $producto->id,
            'version' => '2026010100',
            'status' => 'active',
            'created_by' => auth()->id(),
        ]);

        Tutorial::create([
            'tutorial_version_id' => $tutoriales->id,
            'title' => 'Uno',
            'videoid' => '76979871',
            'platform' => 'vimeo',
            'sort_order' => 1,
            'status' => 'published',
            'created_by' => auth()->id(),
        ]);

        Livewire::test(TutorialCreate::class, ['product' => $producto, 'tutorialVersion' => $tutoriales])
            ->assertSet('sort_order', 2);
    }
}
