<?php

namespace App\Http\Controllers;

use App\Mail\ContactRequestMail;
use App\Models\Customer;
use App\Models\InboundMail;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Illuminate\View\View;

/**
 * „Sprechen Sie uns an" als Seite, nicht als `mailto:`.
 *
 * Der Knopf unter den Paketen zeigte auf `mailto:`, und der tut auf den meisten
 * Geräten nichts Sichtbares: ohne eingerichtetes Mailprogramm passiert gar
 * nichts, im Browser öffnet sich bestenfalls ein Dialog, den niemand erwartet
 * hat. Das ist ausgerechnet an der Stelle fatal, an der das Selbstbedienen
 * aufhört und ein Gespräch beginnen soll — wer hier klickt, hat sich schon
 * entschieden zu fragen.
 *
 * Eine Seite statt eines Modals: die öffentliche Website lädt kein Livewire,
 * ein gewöhnlicher Formular-POST kommt also auch dann an, wenn JavaScript
 * scheitert. Und eine Seite hat eine Adresse — sie lässt sich aus einer Mail
 * heraus verlinken, ein Modal nicht.
 */
class ContactController extends Controller
{
    /** Themen, die das Formular kennt. Alles andere wird zu `general`. */
    private const TOPICS = ['enterprise', 'general'];

    public function show(Request $request): View
    {
        $topic = (string) $request->query('thema', 'general');

        return view('contact', [
            'topic' => in_array($topic, self::TOPICS, true) ? $topic : 'general',
            'sent' => $request->session()->get('contact.sent', false),
        ]);
    }

    public function send(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'company' => ['nullable', 'string', 'max:120'],
            'name' => ['required', 'string', 'max:120'],
            'email' => ['required', 'email:rfc', 'max:190'],
            'phone' => ['nullable', 'string', 'max:60'],
            'message' => ['required', 'string', 'min:10', 'max:4000'],
            'topic' => ['nullable', 'string', 'in:'.implode(',', self::TOPICS)],
            // Honigtopf: ein Feld, das im Browser niemand sieht und ein
            // Formularroboter trotzdem ausfüllt. `filled` statt einer eigenen
            // Regel, damit die Meldung, die ein Mensch nie zu sehen bekommt,
            // auch keine eigene Übersetzung braucht.
            'website' => ['nullable', 'prohibited'],
        ], [], [
            'name' => 'Name',
            'email' => 'E-Mail-Adresse',
            'message' => 'Nachricht',
        ]);

        $enquiry = [
            'company' => $data['company'] ?? null,
            'name' => $data['name'],
            'email' => $data['email'],
            'phone' => $data['phone'] ?? null,
            'message' => $data['message'],
            'topic' => $data['topic'] ?? 'general',
        ];

        // ZUERST festhalten, dann erst benachrichtigen.
        //
        // Die Mail war anfangs die einzige Ablage, und das ging in dem Moment
        // schief, in dem der Versand scheiterte: der Besucher las „Ihre Anfrage
        // ist da", und die Anfrage lag in `failed_jobs`, wo niemand nachsieht.
        // Genau so ist es hier beim ersten Versuch passiert — das Postfach
        // support@ hatte kein eigenes SMTP-Konto, und der Server wies den
        // Absender ab.
        //
        // Der Posteingang der Konsole ist ohnehin die richtige Ablage: er
        // existiert für „was Kunden uns geschrieben haben", zeigt Nicht-
        // Zugeordnetes zuerst und nennt in seinem eigenen Kopfkommentar die
        // neue Anfrage von einer unbekannten Adresse als den Fall, der nicht
        // untergehen darf. Eine Website-Anfrage IST dieser Fall.
        $this->record($enquiry);

        // Die Mail ist ab hier eine Benachrichtigung, kein Ablageort. Scheitert
        // sie, steht die Anfrage trotzdem in der Konsole.
        Mail::send(new ContactRequestMail($enquiry));

        // Zurück auf dieselbe Seite, mit einer Fahne in der Sitzung statt einer
        // Kennung in der Adresse: ein Neuladen zeigt danach wieder das leere
        // Formular und nicht dauerhaft eine Bestätigung für etwas, das längst
        // erledigt ist.
        return redirect()
            ->route('contact')
            ->with('contact.sent', true);
    }

    /**
     * Die Anfrage in den Posteingang der Konsole legen.
     *
     * @param  array{company: ?string, name: string, email: string, phone: ?string, message: string, topic: ?string}  $enquiry
     */
    private function record(array $enquiry): void
    {
        InboundMail::create([
            // Dieselbe Zuordnungsregel wie beim Abholen echter Mail
            // (IngestInboundMail): schreibt ein bestehender Kunde über das
            // Formular, hängt die Anfrage an ihm. Sonst bleibt sie ohne
            // Zuordnung — und steht damit im Posteingang ganz oben.
            'customer_id' => Customer::query()->where('email', $enquiry['email'])->value('id'),
            // Synthetisch, weil eine Formularanfrage keine echte Message-ID hat
            // und die Spalte eindeutig sein muss. Das Präfix macht später
            // erkennbar, dass dieser Eintrag nicht aus dem Postfach kam.
            'message_id' => 'web-'.Str::uuid().'@'.(parse_url((string) config('app.url'), PHP_URL_HOST) ?: 'clupilot'),
            'from_email' => $enquiry['email'],
            'from_name' => $enquiry['company']
                ? $enquiry['name'].' · '.$enquiry['company']
                : $enquiry['name'],
            'subject' => ContactRequestMail::subjectFor($enquiry),
            'body' => $this->bodyFor($enquiry),
            'received_at' => now(),
        ]);
    }

    /**
     * Was der Posteingang als Nachricht zeigt.
     *
     * Die Telefonnummer gehört mit hinein: `inbound_mails` hat kein Feld dafür,
     * und eine Nummer, die jemand extra angegeben hat, im Formular zu verlieren
     * hieße, ihn nicht anrufen zu können.
     *
     * @param  array{phone: ?string, message: string}  $enquiry
     */
    private function bodyFor(array $enquiry): string
    {
        return $enquiry['phone']
            ? $enquiry['message']."\n\n—\nTelefon: ".$enquiry['phone']
            : $enquiry['message'];
    }
}
