<?php

namespace Drupal\social\Behat\Mailpit;

/**
 * Represents a fully populated message in the Mailpit API.
 */
readonly class Message {

  use AssertDataStructureTrait;

  /**
   * Create a new message data object.
   *
   * @param string $id
   *   The Mailpit ID of the email.
   * @param string $messageId
   *   Message-ID is a unique identifier for a digital message.
   *   If present, are generated by the client program sending the email[2] or
   *   by the first mail server.[3] A common method of generating such ID is by
   *   combining the time and domain name, for example:
   *   950124.162336@param bool $read
   *   Whether the message has been read or not.
   * @param Addressee $from
   *   The sender of the email.
   * @param Addressee[] $to
   *   The recipients of the email.
   * @param Addressee[] $cc
   *   The carbon copy recipients of the email.
   * @param Addressee[] $bcc
   *   The blind carbon copy recipients of the email.
   * @param Addressee[] $replyTo
   *   The reply to list of the email.
   * @param string $returnPath
   *   The designated email address where bounced messages and other email
   *   feedback are sent.
   * @param string $subject
   *   The subject of the email.
   * @param ListUnsubscribe $listUnsubscribe
   *   The email header that contains specific instructions about a brand’s
   *   unsubscribe process that inbox providers can use to power native
   *   unsubscribe functionality in their inboxes.
   * @param \DateTimeImmutable $date
   *   The date the email was sent.
   * @param string[] $tags
   *   Any Mailpit tags that are associated with the email.
   * @param string $username
   *   The Mailpit recipient username.
   * @param string $text
   *   The text version of the email.
   * @param string $html
   *   The HTML version of the email.
   * @param int $size
   *   The size in bytes of the email.
   * @param Attachment[] $inline
   *   Any inline files in the email.
   * @param Attachment[] $attachments
   *   A list of attachments in the email.
   *
   *@example.com.
   */
  public function __construct(
    public string $id,
    public string $messageId,
    public bool $read,
    public Addressee $from,
    public array $to,
    public array $cc,
    public array $bcc,
    public array $replyTo,
    public string $returnPath,
    public string $subject,
    public ListUnsubscribe $listUnsubscribe,
    public \DateTimeImmutable $date,
    public array $tags,
    public string $username,
    public string $text,
    public string $html,
    public int $size,
    public array $inline,
    public array $attachments,
  ) {}

  /**
   * Create the data object from an array of values.
   *
   * @param array $data
   *   The array of values as provided by the API.
   *
   * @return self
   *   The data object.
   */
  public static function fromArray(array $data) : self {
    static::assertHasFields(
      $data,
      [
        "ID",
        "MessageID",
        "Read",
        "From",
        "To",
        "Cc",
        "Bcc",
        "ReplyTo",
        "ReturnPath",
        "Subject",
        "ListUnsubscribe",
        "Date",
        'Tags',
        'Username',
        'Text',
        'HTML',
        'Size',
        'Inline',
        'Attachments',
      ],
      "Unexpected JSON object from Mailpit, expected message in format from `/api/v1/#get-/api/v1/message/-ID-` documentation",
    );

    return new static(
      id: $data['ID'],
      messageId: $data['MessageID'],
      read: $data['Read'],
      from: Addressee::fromArray($data['From']),
      to: array_map([Addressee::class, "fromArray"], $data['To']),
      cc: array_map([Addressee::class, "fromArray"], $data['Cc'] ?? []),
      bcc: array_map([Addressee::class, "fromArray"], $data['Bcc'] ?? []),
      replyTo: array_map([Addressee::class, "fromArray"], $data['ReplyTo'] ?? []),
      returnPath: $data['ReturnPath'],
      subject: $data['Subject'],
      listUnsubscribe: ListUnsubscribe::fromArray($data['ListUnsubscribe']),
      date: new \DateTimeImmutable($data['Date']),
      tags: $data['Tags'],
      username: $data['Username'],
      text: $data['Text'],
      html: $data['HTML'],
      size: $data['Size'],
      inline: array_map([Attachment::class, "fromArray"], $data['Inline']),
      attachments: array_map([Attachment::class, "fromArray"], $data['Attachments']),
    );
  }

}
