<?php

namespace App\Livewire\Auth;

use App\Models\Customer;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use Livewire\Component;

/**
 * Where somebody waits between registering and confirming.
 *
 * Signed in but not through: the account exists, and nothing in the portal
 * opens until the address is confirmed. The page offers the two things that can
 * move somebody forward — send it again, or throw the account away and start
 * over with the address they meant.
 *
 * "Abmelden und neu registrieren" used to be the second one, and it was wrong
 * twice: signing out does not free the address, so registering again with the
 * same one fails — and every abandoned attempt stays in `users` for ever. The
 * button deletes the account instead, and anything nobody comes back to is
 * removed after PruneUnverifiedAccounts::AFTER_DAYS days.
 *
 * Fortify would own this page, but 'views' => false: the app renders its own
 * screens (R1/R2) and Fortify keeps only the POST actions.
 */
#[Layout('layouts.portal')]
class VerifyEmail extends Component
{
    /**
     * Six a minute is generous for a person and useless for anything else.
     * Without it this is a button that makes the server send mail to an
     * arbitrary address as fast as it can be clicked.
     */
    private const PER_MINUTE = 6;

    /**
     * Somebody already through has no step left, and telling them they do is
     * how a confirmed account goes looking for a mail it does not need. The
     * `verified` middleware only guards the other direction — it keeps the
     * unconfirmed out of the portal and has nothing to say about this page.
     */
    public function mount()
    {
        if (Auth::user()?->hasVerifiedEmail()) {
            return $this->redirectRoute('dashboard', navigate: false);
        }

        return null;
    }

    public function resend(): void
    {
        $user = Auth::user();

        // Already through — a stale tab, or the link opened in another window.
        // Sending another confirmation for an address that no longer needs one
        // is how somebody ends up chasing a mail they do not need.
        if ($user === null || $user->hasVerifiedEmail()) {
            $this->redirectRoute('dashboard', navigate: true);

            return;
        }

        $key = 'verify-resend:'.$user->getKey();

        if (RateLimiter::tooManyAttempts($key, self::PER_MINUTE)) {
            $this->dispatch('notify', message: __('verify_email.notice_hint'));

            return;
        }

        RateLimiter::hit($key, 60);
        $user->sendEmailVerificationNotification();

        $this->dispatch('notify', message: __('verify_email.notice_sent'));
    }

    /**
     * Throw this registration away.
     *
     * Only an UNCONFIRMED account, and only one nothing is attached to. The
     * webhook creates a customer's login from a paid checkout, and such a user
     * can sit here unconfirmed while already having a contract — deleting that
     * would be data loss dressed up as a convenience. It refuses and says where
     * to go instead.
     *
     * R23: the confirmation is a modal, not a browser dialog. This method is
     * what the modal's event reaches, and it re-checks everything itself
     * because a modal is reachable without this page's own guards.
     */
    #[On('own-account-delete-confirmed')]
    public function deleteAccount()
    {
        $user = Auth::user();

        if ($user === null) {
            return $this->redirectRoute('login', navigate: false);
        }

        if ($user->hasVerifiedEmail()) {
            // Confirmed accounts are closed, not deleted — that is a different
            // action, with an invoice history behind it (ConfirmCloseAccount).
            return $this->redirectRoute('dashboard', navigate: false);
        }

        if (Customer::query()->where('user_id', $user->getKey())->exists()
            || Customer::query()->where('email', $user->email)->exists()) {
            $this->dispatch('notify', message: __('verify_email.delete_has_contract'));

            return null;
        }

        Auth::guard('web')->logout();
        $user->delete();

        session()->invalidate();
        session()->regenerateToken();
        session()->flash('status', __('verify_email.deleted'));

        return $this->redirectRoute('register', navigate: false);
    }

    public function render()
    {
        return view('livewire.auth.verify-email', [
            'email' => Auth::user()?->getEmailForVerification() ?? '',
        ]);
    }
}
