<?php declare(strict_types=1);

require_once __DIR__ . '/../common/QrbException.php';
require_once __DIR__ . '/QrbMultiLanguageText.php';

// Holds the QR bill mail data.
final class QrbMailData
{
    public const KEY_MAIL_DATA = "MailData";
    
    // key constants (public for unit test)
    public const KEY_FROM_ADDRESS = "fromAddress";
    public const KEY_FROM_NAME    = "fromName";
    public const KEY_SUBJECT      = "subject";
    public const KEY_ATT_NAME     = "attachmentName";
        
    private string                   $fromAddress;
    private string                   $fromName;
    private QrbMultiLanguageText  $subject;
    private ?QrbMultiLanguageText $attachmentName = NULL;
    private QrbMultiLanguageText  $htmlBody;
    
    // Validates mail data from the given associative array.
    // mailData["fromAddress"]:    checked to be a valid e-mail address
    // mailData["fromName"]:       taken as is
    // mailData["subject"]:        checked for valid multi language
    //                             (default key and keys in additionalLanguages must exist)
    // mailData["attachmentName"]: optional; if hasAttachment is true, 
    //                             checked for valid multi language
    //                             (default key and keys in additionalLanguages must exist)
    public static function validate(array $mailData, bool $hasAttachment, array $additionalLanguages)
    {
        if (! array_key_exists(self::KEY_MAIL_DATA, $mailData))
            throw new QrbException(
                static::class . " - surrounding key 'MailData' of mail data does not exist",
                "exception.mailData.surroundingKeyDoesNotExist");
        $mailDataContents = $mailData[self::KEY_MAIL_DATA];

        if (! array_key_exists(self::KEY_FROM_ADDRESS, $mailDataContents))
            throw new QrbException(
                static::class . " - key 'fromAddress' for e-mail from address of mail data does not exist",
                "exception.mailData.fromAddressDoesNotExist");
        if (filter_var($mailDataContents[self::KEY_FROM_ADDRESS], FILTER_VALIDATE_EMAIL) === false)
            throw new QrbException(
                static::class . " - Invalid fromAddress '{$mailDataContents[self::KEY_FROM_ADDRESS]}'",
                "exception.mailData.fromAddressInvalid");
        if (! array_key_exists(self::KEY_FROM_NAME, $mailDataContents))
            throw new QrbException(
                static::class . " - key 'fromName' for e-mail from name of mail data does not exist",
                "exception.mailData.fromNameDoesNotExist");
        if (! array_key_exists(self::KEY_SUBJECT, $mailDataContents))
            throw new QrbException(
                static::class . " - key 'subject' for e-mail subject of mail data does not exist",
                "exception.mailData.subjectDoesNotExist");
        QrbMultiLanguageText::validate(self::KEY_SUBJECT, $mailDataContents[self::KEY_SUBJECT], $additionalLanguages);
        
        if ($hasAttachment)
        {
            if (! array_key_exists(self::KEY_ATT_NAME, $mailDataContents))
                throw new QrbException(
                    static::class . " - key 'attachmentName' for e-mail attachment name of mail data does not exist",
                    "exception.mailData.attachmentNameDoesNotExist");
            QrbMultiLanguageText::validate(self::KEY_ATT_NAME, $mailDataContents[self::KEY_ATT_NAME], $additionalLanguages);
        }
    }
    
    // Creates a mail data instance from the given associative array and the given multi-language HTML body.
    // mailData["fromAddress"]:    checked to be a valid e-mail address
    // mailData["fromName"]:       taken as is
    // mailData["subject"]:        checked for valid multi language
    //                             (default key and keys in additionalLanguages must exist)
    // mailData["attachmentName"]: optional; if hasAttachment is true, 
    //                             checked for valid multi language 
    //                             (default key and keys in additionalLanguages must exist)
    // mailHtmlBody:               taken as is
    public function __construct(array                   $mailData, 
                                QrbMultiLanguageText $mailHtmlBody, 
                                bool                    $hasAttachment,
                                array                   $supportedLanguages,
                                array                   $additionalLanguages)
    {
        self::validate($mailData, $hasAttachment, $additionalLanguages);
            
        $mailDataContents = $mailData[self::KEY_MAIL_DATA];
        
        $this->fromAddress    = $mailDataContents[self::KEY_FROM_ADDRESS];
        $this->fromName       = $mailDataContents[self::KEY_FROM_NAME];
        $this->subject        = 
            QrbMultiLanguageText::fromJsonArray(self::KEY_SUBJECT,
                                                   $mailDataContents[self::KEY_SUBJECT], 
                                                   $supportedLanguages,
                                                   $additionalLanguages);
        if ($hasAttachment)
            $this->attachmentName = 
                QrbMultiLanguageText::fromJsonArray(self::KEY_ATT_NAME,
                                                       $mailDataContents[self::KEY_ATT_NAME], 
                                                       $supportedLanguages,
                                                       $additionalLanguages);
        $this->htmlBody       = $mailHtmlBody;
    }

    // Checks whether localized data for the given language exists.
    // If some data is missing then the given missingKeys is updated.
    public function existsLocalizedData(string $language, array &$missingKeys) : void
    {
        if (! $this->existsLocalizedSubject($language))
            $missingKeys[self::KEY_MAIL_DATA . ".json"][self::KEY_SUBJECT] = true;
        if (! $this->existsLocalizedAttachmentName($language))
            $missingKeys[self::KEY_MAIL_DATA . ".json"][self::KEY_ATT_NAME] = true;
        if (! $this->existsLocalizedHtmlBody($language))
            $missingKeys["MailBody_" . $language . ".html"] = true;
    }

    // returns the from address
    public function getFromAddress() : string
    {
        return $this->fromAddress;
    }
    
    // returns the from name
    public function getFromName() : string
    {
        return $this->fromName;
    }
    
    // checks whether the subject supports the given language
    private function existsLocalizedSubject(string $language) : bool
    {
        return $this->subject->existsLocalizedText($language);
    }
    
    // returns the subject in the given language
    public function getSubject(string $language) : string
    {
        return $this->subject->getText($language);
    }
    
    // checks whether the attachment name supports the given language
    private function existsLocalizedAttachmentName(string $language) : bool
    {
        if ($this->attachmentName == NULL)
            return true;    // fake this
            
        return $this->attachmentName->existsLocalizedText($language);
    }

    // returns the attachment name in the given language, may be NULL if no attachment
    public function getAttachmentName(string $language) : ?string
    {
        if ($this->attachmentName == NULL)
            return NULL;    // fake this
            
        return $this->attachmentName->getText($language);
    }

    // checks whether the mail body supports the given language
    private function existsLocalizedHtmlBody(string $language) : bool
    {
        return $this->htmlBody->existsLocalizedText($language);
    }
    
    // returns the mail body in the given language
    public function getHtmlBody(string $language) : string
    {
        return $this->htmlBody->getText($language);
    }

    public function __toString()
    {
        return  "\n\tfromAddress    = '{$this->fromAddress}'"
              . "\n\tfromName       = '{$this->fromName}'"
              . "\n\tsubject: {$this->subject}"
              . "\n\tattachmentName: {$this->attachmentName}"
        // mail body is muck too large to print, so just print "available"
//               . "\n\thtmlBody: {$this->htmlBody}"
              . "\n\thtmlBody       = '" . ( $this->htmlBody ? "available" : "NULL" ) . "'"
              ;
    }
}

?>
