<?php

namespace App\Notifications;

use App\Mail\Concerns\SendsFromMailbox;
use App\Models\Datacenter;
use App\Models\Instance;
use App\Services\Mail\MailCatalogue;
use App\Services\Mail\MailPurpose;
use App\Support\ProvisioningSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

/**
 * Announces that provisioning has finished. Carries NO credential.
 *
 * The initial admin password used to travel here in clear text — crossing
 * third-party mail servers and then sitting in an inbox forever, the weakest
 * link in the chain. It now lives on the instance instead
 * (Instance::$admin_password, encrypted — see CompleteProvisioning) until the
 * customer acknowledges it on their dashboard, at which point it is deleted
 * for good. This mail only says the cloud is ready and where to find them.
 *
 * Sent SYNCHRONOUSLY from CompleteProvisioning (not queued): the step only
 * records the `credentials_sent` breadcrumb AFTER the send returns, so a mail
 * failure re-runs the step instead of losing the breadcrumb in a failed queue
 * job. Delivery is at-least-once — a crash in the tiny window after send but
 * before the breadcrumb can re-send a duplicate welcome email, which is
 * preferable to the customer never being told their cloud is ready.
 */
class CloudReady extends Notification
{
    use Queueable, SendsFromMailbox;

    public function __construct(
        public Instance $instance,
    ) {}

    /** @return array<int, string> */
    public function via(object $notifiable): array
    {
        return ['mail'];
    }

    public function toMail(object $notifiable): MailMessage
    {
        $url = 'https://'.$this->instance->subdomain.'.'.ProvisioningSettings::dnsZone();

        [$from, $replyTo] = $this->mailboxAddresses(MailPurpose::PROVISIONING, 'cloud-ready');

        // Derselbe Schlüssel wie eine Zeile darüber: Umschlag UND Anmeldung
        // folgen der Wegwahl, sonst ginge diese Mail mit dem From des einen
        // Postfachs durch die SMTP-Sitzung eines anderen.
        $message = (new MailMessage)->mailer(MailCatalogue::mailer('cloud-ready'));

        if ($from !== null) {
            $message->from($from->address, $from->name);
        }

        if ($replyTo !== null) {
            $message->replyTo($replyTo->address, $replyTo->name);
        }

        // ->view() rather than the notification's markdown builder: the default
        // arrives with the framework's logo, button and footer, and this is the
        // mail that greets somebody on the day their product starts working.
        // Kept as a Notification rather than turned into a Mailable, because
        // CompleteProvisioning depends on it being sent synchronously and on
        // what happens after the send returns.
        return $message
            ->subject(__('provisioning.mail.ready_subject'))
            ->view('mail.cloud-ready', [
                'name' => (string) ($notifiable->name ?? ''),
                'url' => $url,
                'plan' => $this->instance->plan,
                'storage' => __('provisioning.mail.value_storage', ['gb' => $this->instance->quota_gb]),
                'location' => $this->location(),
                'dashboardUrl' => route('dashboard'),
            ]);
    }

    /**
     * The datacenter in words, falling back to the code.
     *
     * Read through the host, because an instance knows which machine it is on
     * and a machine knows where it stands. A missing name is not worth a second
     * query or an empty row — the code is what the customer chose at checkout
     * and will recognise.
     */
    private function location(): string
    {
        $code = $this->instance->host?->datacenter;

        if (! is_string($code) || $code === '') {
            return '—';
        }

        $datacenter = Datacenter::query()->where('code', $code)->first();

        if ($datacenter === null) {
            return $code;
        }

        return $datacenter->facility
            ? $datacenter->name.' · '.$datacenter->facility
            : $datacenter->name;
    }
}
