<?php

namespace App\Livewire;

use App\Livewire\Concerns\ResolvesCustomer;
use App\Models\Seat;
use LivewireUI\Modal\ModalComponent;

/**
 * Edit one seat, in a modal.
 *
 * Editing used to happen in the row itself. It worked and it looked wrong: the
 * row grew, the columns beside it jumped, and a table half in edit mode reads
 * as a rendering fault rather than as a form. Anything with fields of its own
 * gets a modal — see R20.
 *
 * A modal is reachable without passing the page's route middleware, so the
 * customer is resolved here rather than trusted from the caller: the uuid comes
 * from the browser and must never reach across customers.
 */
class EditSeat extends ModalComponent
{
    use ResolvesCustomer;

    public string $uuid = '';

    public string $name = '';

    public string $email = '';

    /** Owners cannot be suspended or removed; everyone can be renamed. */
    public bool $isOwner = false;

    /**
     * Whether the address may still be corrected.
     *
     * Only until the seat has an account in the customer's cloud. From that
     * point the address IS the person: editing it would hand one employee's
     * access to another with nobody told — a transfer of access wearing the
     * clothes of a rename.
     *
     * Die Bedingung hing an `status === 'invited'`, und das trug nicht: NICHTS
     * im Bestand setzt `seats.status` je von 'invited' auf 'active'. Ein
     * eingeladener Sitz blieb damit für immer 'invited' und seine Adresse
     * dauerhaft änderbar — entgegen genau diesem Kommentar. `seats.email`
     * wurde `b@y`, `nc_username` blieb `a@x` (richtig: Nextcloud kann Benutzer
     * nicht umbenennen), und kein Befehl trug die neue Adresse in den Gast.
     * „Erneut senden" schickte danach `user:welcome --reset-password 'a@x'`:
     * das Portal führte `b@y` als Inhaberin des Sitzes, tatsächlich hielt
     * `a@x` den Zugang und bekam jederzeit einen neuen Zurücksetzen-Link.
     *
     * `nc_username` ist die Angabe, die der Kommentar ohnehin meint — genau
     * einmal gesetzt, danach unveränderlich.
     *
     * Der Inhaber-Sitz ist davon AUSGENOMMEN, und diese Ausnahme kam mit dem
     * Umbau dazu: an `status === 'invited'` war seine Adresse nie änderbar,
     * denn er steht immer auf 'active'. An `nc_username` allein wäre sie es —
     * genau so lange, bis die Bereitstellung das Admin-Konto angelegt hat und
     * `linkToInstanceAdmin()` greift.
     *
     * Was dabei entstünde, ist kein Umbenennen: läuft die Adresse des
     * Inhaber-Sitzes von der Kundenadresse weg, legt „Anlegen" mit der echten
     * Adresse eine ZWEITE Zeile für dieselbe Person an — die gegen die
     * Platzgrenze zählt. Der Inhaber-Sitz ist der eine Sitz, dessen Adresse
     * nicht ihm gehört, sondern dem Kundenkonto.
     */
    public bool $addressEditable = false;

    /**
     * Die eine Bedingung, an drei Stellen gebraucht: beim Zeichnen, beim
     * Aufstellen der Regeln und beim Übernehmen. Als Methode statt dreimal
     * abgeschrieben — auseinanderlaufen muss sie nur einmal, um eine Lücke zu
     * sein.
     */
    private function adresseAenderbar(Seat $seat): bool
    {
        return blank($seat->nc_username) && $seat->role !== 'owner';
    }

    public function mount(string $uuid): void
    {
        $seat = $this->seat($uuid);

        abort_if($seat === null, 404);

        $this->uuid = $uuid;
        $this->name = (string) $seat->name;
        $this->email = (string) $seat->email;
        $this->isOwner = $seat->role === 'owner';
        $this->addressEditable = $this->adresseAenderbar($seat);
    }

    public function save()
    {
        $customer = $this->requireCustomer();
        $seat = $this->seat($this->uuid);

        if ($customer === null || $seat === null) {
            return $this->closeModal();
        }

        $rules = ['name' => 'nullable|string|max:255'];

        // Re-read from the record, never from the hydrated property: a forged
        // addressEditable would otherwise open the address of a seat that
        // already has an account in the cloud — or the owner's own.
        if ($this->adresseAenderbar($seat)) {
            $rules['email'] = 'required|email|max:255';
        }

        $data = $this->validate($rules);

        $changes = ['name' => trim($data['name'] ?? '') ?: null];

        if ($this->adresseAenderbar($seat)) {
            $address = trim($data['email']);

            if ($address !== $seat->email) {
                if ($customer->seats()->where('email', $address)->whereKeyNot($seat->id)->exists()) {
                    $this->addError('email', __('users.duplicate'));

                    return null;
                }

                $changes['email'] = $address;
            }
        }

        $seat->update($changes);

        $this->dispatch('notify', message: __('users.saved'));

        return $this->redirectRoute('users', navigate: true);
    }

    private function seat(string $uuid): ?Seat
    {
        return $this->customer()?->seats()->where('uuid', $uuid)->first();
    }

    public function render()
    {
        return view('livewire.edit-seat');
    }
}
