<?php

namespace Tests\Feature;

use App\Models\AuditLog;
use App\Models\Department;
use App\Models\Organization;
use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use App\Models\UserAssignment;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;

class AdministrationTest extends TestCase
{
    use RefreshDatabase;

    public function test_administration_area_requires_administration_mode(): void
    {
        [$user] = $this->superAdministrator();

        $this->actingAs($user)->withSession(['operating_mode' => 'operation'])
            ->get('/administracao')
            ->assertRedirect('/painel')
            ->assertSessionHas('warning');
    }

    public function test_superadministrator_can_create_a_department(): void
    {
        [$user, $organization] = $this->superAdministrator();

        $this->actingAs($user)->withSession([
            'operating_mode' => 'administration',
            'administration_mode_started_at' => now(),
        ])->post('/administracao/departamentos', [
            'organization_id' => $organization->id,
            'code' => 'qualidade',
            'name' => 'Qualidade',
            'description' => 'Unidade de qualidade operacional.',
            'is_active' => '1',
        ])->assertRedirect('/administracao/departamentos');

        $this->assertDatabaseHas('departments', ['code' => 'qualidade', 'name' => 'Qualidade', 'is_active' => true]);
        $this->assertDatabaseHas('audit_logs', ['event' => 'criado', 'auditable_type' => Department::class]);
    }

    public function test_all_administration_pages_render_in_isolated_environment(): void
    {
        [$user, $organization] = $this->superAdministrator();
        Department::query()->create(['organization_id' => $organization->id, 'code' => 'financeiro', 'name' => 'Financeiro']);

        $session = [
            'operating_mode' => 'administration',
            'administration_mode_started_at' => now(),
        ];

        $pages = [
            '/administracao' => 'Centro de controlo do sistema',
            '/administracao/filiais' => 'Filiais',
            '/administracao/filiais/create' => 'Registar nova filial',
            '/administracao/departamentos' => 'Departamentos',
            '/administracao/departamentos/create' => 'Criar departamento',
            '/administracao/utilizadores' => 'Utilizadores',
            '/administracao/utilizadores/create' => 'Criar utilizador',
            '/administracao/perfis' => 'Perfis e permissões',
            '/administracao/perfis/create' => 'Criar perfil',
            '/administracao/configuracoes' => 'Configurações',
            '/auditoria' => 'Auditoria do sistema',
        ];

        foreach ($pages as $url => $text) {
            $this->actingAs($user)->withSession($session)->get($url)->assertOk()->assertSee($text);
        }
    }

    public function test_user_creation_records_assignment_without_exposing_password_in_audit(): void
    {
        [$administrator, $organization, $superRole] = $this->superAdministrator();
        $operator = Role::query()->create(['code' => 'operador', 'name' => 'Operador', 'is_active' => true]);
        $department = Department::query()->create(['organization_id' => $organization->id, 'code' => 'tecnico', 'name' => 'Departamento Técnico']);

        $this->actingAs($administrator)->withSession([
            'operating_mode' => 'administration',
            'administration_mode_started_at' => now(),
        ])->post('/administracao/utilizadores', [
            'name' => 'Técnico de Teste',
            'username' => 'tecnico.teste',
            'email' => 'tecnico@nestab.test',
            'password' => 'Nestab2026',
            'password_confirmation' => 'Nestab2026',
            'organization_id' => $organization->id,
            'department_id' => $department->id,
            'role_ids' => [$operator->id],
            'is_active' => '1',
        ])->assertRedirect('/administracao/utilizadores');

        $created = User::query()->where('username', 'tecnico.teste')->firstOrFail();
        $this->assertTrue(Hash::check('Nestab2026', $created->password));
        $this->assertTrue($created->must_change_password);
        $this->assertDatabaseHas('user_assignments', ['user_id' => $created->id, 'role_id' => $operator->id]);

        $auditPayload = AuditLog::query()->where('auditable_type', User::class)->get()->toJson();
        $this->assertStringNotContainsString('Nestab2026', $auditPayload);
        $this->assertStringNotContainsString($created->password, $auditPayload);
    }

    public function test_role_permission_matrix_can_be_updated(): void
    {
        [$administrator] = $this->superAdministrator();
        $role = Role::query()->create(['code' => 'gestor', 'name' => 'Gestor', 'is_active' => true]);
        $permission = Permission::query()->create([
            'code' => 'clients.view', 'module' => 'clientes', 'action' => 'consultar', 'name' => 'Consultar clientes',
        ]);

        $this->actingAs($administrator)->withSession([
            'operating_mode' => 'administration',
            'administration_mode_started_at' => now(),
        ])->put('/administracao/perfis/'.$role->id, [
            'code' => 'gestor', 'name' => 'Gestor', 'is_active' => '1',
            'permission_ids' => [$permission->id],
        ])->assertRedirect('/administracao/perfis');

        $this->assertDatabaseHas('permission_role', ['role_id' => $role->id, 'permission_id' => $permission->id]);
        $this->assertDatabaseHas('audit_logs', ['event' => 'permissoes_actualizadas', 'auditable_id' => $role->id]);
    }

    private function superAdministrator(): array
    {
        $organization = Organization::query()->create(['code' => 'NESTAB', 'name' => 'NESTAB SECURITY GPS']);
        $role = Role::query()->create([
            'code' => 'superadministrador', 'name' => 'Superadministrador',
            'is_privileged' => true, 'is_system' => true, 'is_active' => true,
        ]);
        $user = User::query()->create([
            'name' => 'Administrador de Teste', 'username' => 'admin.teste',
            'email' => 'admin@nestab.test', 'password' => Hash::make('Nestab2026'),
            'is_active' => true, 'must_change_password' => false,
        ]);
        UserAssignment::query()->create([
            'user_id' => $user->id, 'organization_id' => $organization->id,
            'role_id' => $role->id, 'is_primary' => true, 'is_active' => true,
        ]);

        return [$user, $organization, $role];
    }
}
