<?php

namespace Tests\Feature\Authorization;

use App\Domains\Authorization\Models\Permission;
use App\Domains\Authorization\Models\Role;
use App\Domains\Authorization\Models\RolePermission;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class RolePermissionModelTest extends TestCase
{
    use RefreshDatabase;

    public function test_authorization_tables_have_the_expected_columns(): void
    {
        $this->assertEqualsCanonicalizing([
            'id',
            'codigo',
            'nombre',
            'descripcion',
            'created_at',
            'updated_at',
        ], Schema::getColumnListing('permisos'));

        $this->assertEqualsCanonicalizing([
            'id',
            'codigo',
            'nombre',
            'descripcion',
            'created_at',
            'updated_at',
        ], Schema::getColumnListing('roles'));

        $this->assertEqualsCanonicalizing([
            'id',
            'codigo_permiso',
            'rol_codigo',
            'created_at',
            'updated_at',
        ], Schema::getColumnListing('roles_permisos'));
    }

    public function test_a_role_and_permission_can_be_related_by_their_codes(): void
    {
        $role = Role::query()->create([
            'codigo' => 'administrador',
            'nombre' => 'Administrador',
            'descripcion' => 'Administra la tienda.',
        ]);
        $permission = Permission::query()->create([
            'codigo' => 'catalogo.editar',
            'nombre' => 'Editar catálogo',
        ]);

        $role->permissions()->attach($permission->codigo);

        $this->assertTrue($role->permissions()->firstOrFail()->is($permission));
        $this->assertTrue($permission->roles()->firstOrFail()->is($role));
        $this->assertDatabaseHas('roles_permisos', [
            'rol_codigo' => $role->codigo,
            'codigo_permiso' => $permission->codigo,
        ]);
    }

    public function test_the_pivot_model_exposes_its_role_and_permission(): void
    {
        $role = Role::query()->create([
            'codigo' => 'editor',
            'nombre' => 'Editor',
        ]);
        $permission = Permission::query()->create([
            'codigo' => 'catalogo.editar',
            'nombre' => 'Editar catálogo',
        ]);
        $assignment = RolePermission::query()->create([
            'rol_codigo' => $role->codigo,
            'codigo_permiso' => $permission->codigo,
        ]);

        $this->assertTrue($assignment->role->is($role));
        $this->assertTrue($assignment->permission->is($permission));
    }

    public function test_a_permission_cannot_be_assigned_twice_to_the_same_role(): void
    {
        $role = Role::query()->create([
            'codigo' => 'editor',
            'nombre' => 'Editor',
        ]);
        $permission = Permission::query()->create([
            'codigo' => 'catalogo.editar',
            'nombre' => 'Editar catálogo',
        ]);
        $role->permissions()->attach($permission->codigo);

        $this->expectException(QueryException::class);

        $role->permissions()->attach($permission->codigo);
    }

    public function test_deleting_a_role_removes_its_permission_assignments(): void
    {
        $role = Role::query()->create([
            'codigo' => 'editor',
            'nombre' => 'Editor',
        ]);
        $permission = Permission::query()->create([
            'codigo' => 'catalogo.editar',
            'nombre' => 'Editar catálogo',
        ]);
        $role->permissions()->attach($permission->codigo);

        $role->delete();

        $this->assertDatabaseMissing('roles_permisos', [
            'rol_codigo' => $role->codigo,
            'codigo_permiso' => $permission->codigo,
        ]);
        $this->assertDatabaseHas('permisos', [
            'codigo' => $permission->codigo,
        ]);
    }
}
