<?php

namespace App\Mail;

use App\Mail\Concerns\RidesALane;
use App\Mail\Concerns\SendsFromMailbox;
use App\Models\Datacenter;
use App\Models\Order;
use App\Services\Mail\MailCatalogue;
use App\Services\Mail\MailPurpose;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

/**
 * "We have your order, and here is what happens next."
 *
 * Sent when the payment lands, not when the machine is ready — those are
 * minutes apart at best and can be much longer, and a customer who has just
 * been charged and heard nothing assumes the worst about both.
 *
 * From the BILLING mailbox: it is a record of a payment, and a reply to it is
 * a question about money rather than about a server.
 *
 * Deliberately says nothing about when the cloud will be ready. Provisioning
 * takes as long as it takes, CloudReady announces the end of it, and a
 * promised time that slips is worse than no promise at all.
 */
class OrderConfirmationMail extends Mailable implements ShouldQueue
{
    use Queueable, RidesALane, SendsFromMailbox, SerializesModels;

    public function __construct(public Order $order, public string $name)
    {
        // The mailer, alongside the From. A purpose mailbox authenticates with
        // its OWN account, and a mail server lets an account send only from the
        // address it owns — so a From of billing@ over the default mailer's
        // no-reply@ login is answered "553 Sender address rejected: not owned by
        // user". Setting the From from a mailbox and leaving the mailer at the
        // default is a mail that renders perfectly and never arrives.
        $this->mailer(MailCatalogue::mailer('order-confirmation'));
    }

    public function envelope(): Envelope
    {
        return $this->mailboxEnvelope(
            MailPurpose::BILLING,
            __('orders.mail_subject', ['number' => $this->order->uuid ?? $this->order->id]),
            'order-confirmation',
        );
    }

    public function content(): Content
    {
        return new Content(view: 'mail.order-confirmation', with: [
            'name' => $this->name,
            'order' => $this->order,
            // Through the model, so the cart, the invoice list and this mail
            // cannot each invent their own wording for the same row.
            'label' => $this->order->label(),
            'amount' => $this->amount(),
            'location' => $this->location(),
            'invoicesUrl' => route('invoices'),
        ]);
    }

    /** The charge, formatted where the currency is known rather than in a view. */
    private function amount(): string
    {
        return number_format($this->order->amount_cents / 100, 2, ',', '.')
            .' '.strtoupper((string) $this->order->currency);
    }

    private function location(): string
    {
        $datacenter = Datacenter::query()
            ->where('code', $this->order->datacenter)
            ->first();

        if ($datacenter === null) {
            return (string) $this->order->datacenter;
        }

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