<?php

namespace App\Support;

use Illuminate\Validation\Rules\Password;

/**
 * Wie lang ein Passwort in dieser Installation sein muss — an einer Stelle.
 *
 * Vorher gab es die Regel dreimal, mit drei verschiedenen Antworten:
 * `ResetPassword` verlangte fest `min:12`, `CreateAdmin` `Password::min(12)`,
 * und alles über `PasswordValidationRules` bekam `Password::default()` — also
 * Laravels acht. Derselbe Kunde brauchte beim Zurücksetzen zwölf Zeichen und
 * bei der Registrierung acht, und einstellbar war nichts davon.
 *
 * Gemeldet wurde die Zwölf als „zu lang". Die eigentliche Auffälligkeit war,
 * dass es die Regel dreimal gibt: drei Stellen, die dieselbe Frage
 * verschieden beantworten, laufen auseinander — hier waren sie es schon.
 *
 * Geklemmt statt abgelehnt: der Wert kommt aus einem Formular im Adminbereich,
 * und eine stillschweigend gespeicherte 1 wäre schlimmer als eine sichtbar auf
 * 6 geklemmte Eingabe.
 */
final class PasswordPolicy
{
    public const SETTING = 'security.password_min_length';

    /**
     * Die kürzeste Länge, die diese Installation zulässt.
     *
     * Sechs ist wenig. Es ist die ausdrückliche Vorgabe des Betreibers
     * (31.7.2026, „6 ist mindestens"), und die Zahl steht direkt neben dem
     * Feld, an dem sie sich erhöhen lässt.
     */
    public const FLOOR = 6;

    /** bcrypt schneidet jenseits von 72 Byte ohnehin ab; 128 ist reichlich Luft. */
    public const CEILING = 128;

    public const DEFAULT_LENGTH = 6;

    public static function minLength(): int
    {
        $stored = Settings::get(self::SETTING);

        return self::clamp(is_numeric($stored) ? (int) $stored : self::DEFAULT_LENGTH);
    }

    public static function set(int $length): void
    {
        Settings::set(self::SETTING, self::clamp($length));
    }

    /**
     * Die Regeln OHNE `confirmed`.
     *
     * Die Bestätigung hängt am Formular, nicht an der Richtlinie: `CreateAdmin`
     * fragt auf der Kommandozeile einmal, jedes Formular zweimal. Wer sie
     * braucht, hängt sie an.
     *
     * @return array<int, mixed>
     */
    public static function rules(): array
    {
        return ['required', 'string', Password::min(self::minLength())];
    }

    private static function clamp(int $length): int
    {
        return max(self::FLOOR, min(self::CEILING, $length));
    }
}
