<?php

use App\Livewire\Auth\ResetPassword;
use App\Models\User;
use App\Support\PasswordPolicy;
use App\Support\Settings;
use Illuminate\Support\Facades\Password as PasswordBroker;
use Livewire\Livewire;

/**
 * Diese Installation hatte DREI Passwortregeln nebeneinander und keine davon
 * einstellbar:
 *
 *   App\Livewire\Auth\ResetPassword   `min:12`, fest im Attribut
 *   App\Console\Commands\CreateAdmin  Password::min(12)
 *   PasswordValidationRules           Password::default() — also Laravels 8
 *
 * Ein Kunde, der sein Passwort zurücksetzte, musste zwölf Zeichen nehmen;
 * derselbe Kunde bei der Registrierung acht. Gemeldet wurde die Zwölf, und beim
 * Nachsehen war die eigentliche Auffälligkeit, dass es die Regel dreimal gibt.
 */
beforeEach(function () {
    Settings::forget(PasswordPolicy::SETTING);
});

it('starts at six characters', function () {
    expect(PasswordPolicy::minLength())->toBe(6);
});

it('lets the console set the length, within a floor and a ceiling', function () {
    PasswordPolicy::set(10);
    expect(PasswordPolicy::minLength())->toBe(10);

    // Unterhalb der Grenze wird geklemmt, nicht abgelehnt: der Wert kommt aus
    // einem Formular, und eine stillschweigend gespeicherte 1 wäre schlimmer
    // als eine sichtbar geklemmte 6.
    PasswordPolicy::set(2);
    expect(PasswordPolicy::minLength())->toBe(PasswordPolicy::FLOOR);

    PasswordPolicy::set(9999);
    expect(PasswordPolicy::minLength())->toBe(PasswordPolicy::CEILING);
});

it('accepts a six-character password when resetting', function () {
    // Der gemeldete Fall. Vorher: `min:12`, fest verdrahtet.
    $user = User::factory()->create(['email' => 'kunde@example.test']);
    $token = PasswordBroker::broker()->createToken($user);

    Livewire::test(ResetPassword::class, ['token' => $token])
        ->set('email', $user->email)
        ->set('password', 'abcdef')
        ->set('password_confirmation', 'abcdef')
        ->call('save')
        ->assertHasNoErrors();

    expect($user->fresh()->password)->not->toBe($user->password);
});

it('follows the configured length instead of a number of its own', function () {
    PasswordPolicy::set(10);

    $user = User::factory()->create(['email' => 'kunde@example.test']);
    $token = PasswordBroker::broker()->createToken($user);

    Livewire::test(ResetPassword::class, ['token' => $token])
        ->set('email', $user->email)
        ->set('password', 'abcdefgh')
        ->set('password_confirmation', 'abcdefgh')
        ->call('save')
        ->assertHasErrors('password');
});

it('keeps the rule in one place', function () {
    // Der eigentliche Fund: drei Regeln nebeneinander. Ein Wächter, damit die
    // vierte nicht danebengeschrieben wird.
    $offenders = [];

    foreach (['app/Livewire', 'app/Actions', 'app/Console/Commands', 'app/Http'] as $dir) {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(base_path($dir)));

        foreach ($files as $file) {
            if ($file->getExtension() !== 'php') {
                continue;
            }

            $body = file_get_contents($file->getPathname());

            if (preg_match('/min:\d+\|confirmed|Password::min\(|Password::default\(\)/', $body)) {
                $offenders[] = str_replace(base_path().'/', '', $file->getPathname());
            }
        }
    }

    expect($offenders)->toBe([], 'Passwortlänge gehört in App\Support\PasswordPolicy, nicht hierhin: '.implode(', ', $offenders));
});
