<?php

namespace App\Livewire\Admin;

use App\Models\Host;
use App\Models\Operator;
use App\Services\Terminal\TerminalTicket;
use Livewire\Attributes\Layout;
use Livewire\Component;

/**
 * Die Seite im eigenen Fenster.
 *
 * Sie hat bewusst kein Layout der Konsole: hier steht ein Terminal, das die
 * volle Fläche bekommt, und eine Seitenleiste daneben wäre ein Rahmen um eine
 * Sache, die keinen braucht.
 *
 * Das Ticket entsteht beim Aufruf und lebt dreißig Sekunden — also genau so
 * lange, wie das Fenster zum Verbinden braucht. Wer die Seite offen liegen
 * lässt und später neu lädt, bekommt ein frisches.
 *
 * Berechtigung ZUERST, Host-Suche DANACH: wer `hosts.manage` nicht hat, soll
 * auch nicht per Antwortzeit oder 404-gegen-403 lernen können, ob eine UUID zu
 * einem echten Host gehört.
 *
 * Die Eigenschaft heißt bewusst NICHT `$host` wie der Routenparameter, obwohl
 * das näherliegend gewesen wäre und die Ansicht genau diesen Namen erwartet
 * (siehe render() unten, das ihn dort wieder einsetzt). Livewires eigene
 * `ImplicitRouteBinding` löst JEDE öffentliche, typisierte Eigenschaft aUTOMATISCH
 * gegen einen gleichnamigen Routenparameter auf — unabhängig vom `mount()`
 * -Rumpf. Mit `public Host $host` UND einem Parameter `{host}` in der Route
 * bekam `mount(string $host)` beim Testlauf nicht die UUID, sondern ein
 * bereits (und ungeprüft!) aufgelöstes `Host`-Objekt, von PHP wegen der
 * Typangabe `string` über `__toString()` in JSON verwandelt — und genau die
 * Prüf-Reihenfolge oben ausgehebelt, weil die Auflösung dann VOR jedem
 * `authorize()`-Aufruf passiert. Ein anderer Name für die Eigenschaft nimmt
 * dem Mechanismus die Angriffsfläche, ohne die Route umzubenennen (die
 * Schnittstelle — `route('admin.hosts.terminal', ['host' => …])` — bleibt
 * unverändert, das betrifft nur, wie diese Klasse den Wert intern hält).
 */
#[Layout('layouts.bare')]
class HostTerminal extends Component
{
    public Host $record;

    public string $ticket = '';

    /**
     * Warum hier kein Terminal entstehen kann — ein Merkwort aus
     * `TerminalTicket::blocker()`, oder leer, wenn nichts im Weg steht.
     */
    public string $problem = '';

    public function mount(string $host): void
    {
        $this->authorize('hosts.manage');

        $this->record = Host::query()->where('uuid', $host)->firstOrFail();

        /** @var Operator $operator */
        $operator = auth('operator')->user();

        // Diese Seite wirft nicht. Ein Terminalfenster, das mit Laravels
        // Fehlerseite aufgeht — Klassenname, Dateipfad, Zeilennummer,
        // Quelltextauszug —, ist ein Bruch mitten im Produkt: der Betreiber hat
        // einen Knopf gedrückt und bekommt einen Stacktrace. Was schiefgehen
        // kann, steht in `blocker()` und wird unten in der Sprache dieses
        // Fensters hingeschrieben.
        $this->problem = TerminalTicket::blocker($this->record) ?? '';

        if ($this->problem !== '') {
            return;
        }

        // Der Fangzaun dahinter: `blocker()` kennt die Gründe, mit denen wir
        // rechnen. Reißt `issue()` aus einem, mit dem niemand gerechnet hat
        // (Redis weg, Tresor kaputt), ist die Antwort dieselbe — eine gestaltete
        // Seite statt einer Fehlerseite —, nur ohne Versprechen, woran es lag.
        try {
            $this->ticket = TerminalTicket::issue($this->record, $operator);
        } catch (\Throwable $e) {
            report($e);
            $this->problem = 'unknown';
        }
    }

    public function render()
    {
        // 'host' ist der Name, den die Ansicht erwartet — die Eigenschaft
        // heißt aus dem oben erklärten Grund anders.
        return view('livewire.admin.host-terminal', ['host' => $this->record])
            ->title($this->record->name.' — Terminal');
    }
}
