<?php

declare(strict_types=1);

namespace Tests\Feature\Demo;

use App\Models\Company;
use App\Models\DemoCredential;
use App\Models\User;
use App\Support\Demo;
use App\Support\DemoCredentials;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class DemoCredentialsTest extends TestCase
{
    use DatabaseTransactions;

    #[Test]
    public function it_stores_the_password_encrypted_at_rest(): void
    {
        $cred = DemoCredential::create(['role' => 'admin', 'password' => 'secret-plain-123']);

        // El modelo descifra vía cast.
        $this->assertSame('secret-plain-123', $cred->fresh()->password);

        // En la BD está cifrado (no es el texto plano).
        $raw = DB::table('demo_credentials')->where('role', 'admin')->value('password');
        $this->assertNotSame('secret-plain-123', $raw);
    }

    #[Test]
    public function rotate_sets_and_changes_the_demo_user_passwords(): void
    {
        Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
        Role::firstOrCreate(['name' => 'supervisor', 'guard_name' => 'web']);
        Role::firstOrCreate(['name' => 'collector', 'guard_name' => 'web']);
        $company = Company::factory()->create(['is_demo' => true]);
        foreach (Demo::USERS as $email => $role) {
            // La BD de dev es compartida y puede tener ya un usuario demo persistido
            // con este email (de una corrida real de credify:setup-demo); se borra
            // dentro de la transacción del test (se revierte al final) para poder
            // crear el usuario de factory sin chocar con el unique de `email`.
            User::where('email', $email)->delete();
            User::factory()->create(['email' => $email, 'company_id' => $company->id]);
        }

        DemoCredentials::rotate();

        $cred = DemoCredential::where('role', 'admin')->first();
        $user = User::where('email', 'demo-dueno@credifygo.com')->first();
        $this->assertTrue(Hash::check($cred->password, $user->password));

        $first = $cred->password;
        DemoCredentials::rotate();
        $this->assertNotSame($first, DemoCredential::where('role', 'admin')->first()->password);
    }

    #[Test]
    public function ensure_is_idempotent_when_credentials_exist(): void
    {
        DemoCredential::create(['role' => 'admin', 'password' => 'a']);
        DemoCredential::create(['role' => 'supervisor', 'password' => 'b']);
        DemoCredential::create(['role' => 'collector', 'password' => 'c']);

        DemoCredentials::ensure();

        $this->assertSame('a', DemoCredential::where('role', 'admin')->first()->password);
    }
}
