<?php

namespace App\Livewire\Auth;

use App\Models\Operator;
use App\Support\PasswordPolicy;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Validate;
use Livewire\Component;

/**
 * Das andere Ende des Einladungslinks: hier vergibt ein eingeladener Betreiber
 * sein Passwort.
 *
 * Eigene Seite und nicht die des Portals (R21). Auch wenn beide Seiten dasselbe
 * Formular zeigen, lösen sie gegen verschiedene Broker und damit gegen
 * verschiedene Tabellen ein — ein Betreiber-Token gilt hier und sonst nirgends,
 * ein Kunden-Token nirgends hier. Eine gemeinsame Seite wäre genau die
 * Vermischung, die R21 beendet hat.
 *
 * Der Token wird von Laravels Broker geprüft, nicht hier: er hält den Hash, die
 * Frist und das Löschen nach dem Einlösen. Ein Link, der zweimal funktioniert,
 * entsteht dadurch, dass jemand eines dieser drei Dinge nachbaut.
 *
 * Angemeldet wird danach NIEMAND. Der Link kam per E-Mail, und wer dieses
 * Postfach lesen kann, bekäme sonst die Sitzung gleich dazu — auf einer
 * Konsole, die die ganze Flotte verwaltet. Der Eingeladene tippt das Passwort
 * einmal mehr auf der Anmeldeseite, und dort greift dann auch die
 * Zwei-Faktor-Pflicht, falls der Inhaber sie eingeschaltet hat.
 */
#[Layout('layouts.portal')]
class OperatorSetPassword extends Component
{
    public string $token = '';

    #[Validate('required|email|max:255')]
    public string $email = '';

    public string $password = '';

    public string $password_confirmation = '';

    public bool $done = false;

    /**
     * Die Länge kommt aus PasswordPolicy, nicht aus einem `#[Validate]`-Attribut:
     * ein Attribut ist ein fester String und kann eine Einstellung nicht lesen.
     *
     * @return array<string, mixed>
     */
    protected function rules(): array
    {
        return ['password' => [...PasswordPolicy::rules(), 'confirmed']];
    }

    public function mount(string $token): void
    {
        $this->token = $token;
        // Aus der Adresszeile vorbelegt, aber als Feld sichtbar: eine Mail, die
        // unterwegs umgebrochen wurde, lässt sich so noch von Hand retten.
        $this->email = (string) request()->query('email', '');
    }

    /**
     * NICHT reset(): Livewire\Component::reset() leert Eigenschaften, und eine
     * Komponente, die sie neu deklariert, lädt gar nicht erst.
     */
    public function save(): void
    {
        $this->validate();

        $status = Password::broker('operators')->reset(
            [
                'email' => $this->email,
                'password' => $this->password,
                'password_confirmation' => $this->password_confirmation,
                'token' => $this->token,
            ],
            function (Operator $operator, string $password) {
                $operator->forceFill([
                    'password' => Hash::make($password),
                    // Jede bestehende „Angemeldet bleiben"-Sitzung stirbt mit.
                    // Beim ersten Setzen ist keine da; beim zweiten Weg über
                    // diese Seite — einer erneuten Einladung — sehr wohl.
                    'remember_token' => Str::random(60),
                ])->save();

                event(new PasswordReset($operator));
            },
        );

        if ($status !== Password::PASSWORD_RESET) {
            // EINE Meldung für alle Fehlschläge, und ausdrücklich nicht
            // __($status): NICHT weil passwords.token/passwords.user roh auf
            // der Seite stünden — Laravel liefert dazu eine eigene
            // Übersetzung mit (lang/en/passwords.php im Framework, und
            // fallback_locale ist en), der Schlüssel löst also durchaus auf.
            // Der eigentliche Grund ist ein anderer: die Fehlschläge zu
            // unterscheiden wäre falsch — „diese Adresse kennen wir nicht"
            // verrät einem Fremden, wer Betreiber ist.
            $this->addError('email', __('auth.console_invite_invalid'));

            return;
        }

        $this->done = true;
    }

    public function render()
    {
        return view('livewire.auth.operator-set-password');
    }
}
