<?php
namespace EasyChat\Library\Email;

 
final class MailEnvelope {
    private $to;
    private $from;
    private $from_name;
    private $reply_to;
    private $subject;
    private $text;
    private $message_id;
    private $in_reply_to;
    private $references;
    private $idempotency_key;

    public function __construct(array $data) {
        $this->to = $this->email((string)($data['to'] ?? ''));
        $this->from = $this->email((string)($data['from'] ?? ''));
        $this->reply_to = $this->email((string)($data['reply_to'] ?? $this->from));
        $this->from_name = $this->header((string)($data['from_name'] ?? ''), 128);
        $this->subject = $this->header((string)($data['subject'] ?? 'Ответ EasyChat'), 998);
        $this->text = trim((string)($data['text'] ?? ''));
        $this->message_id = $this->normalizeMessageId((string)($data['message_id'] ?? ''));
        $this->in_reply_to = $this->normalizeMessageId((string)($data['in_reply_to'] ?? ''));
        $references = is_array($data['references'] ?? null) ? $data['references'] : array();
        $this->references = array_values(array_unique(array_filter(array_map(array($this, 'normalizeMessageId'), $references))));
        if ($this->in_reply_to !== '' && !in_array($this->in_reply_to, $this->references, true)) $this->references[] = $this->in_reply_to;
        $this->references = array_slice($this->references, -20);
        $this->idempotency_key = preg_replace('/[^a-zA-Z0-9_.:-]/', '', (string)($data['idempotency_key'] ?? ''));
        if ($this->to === '' || $this->from === '' || $this->text === '' || $this->message_id === '') throw new \InvalidArgumentException('email_envelope_invalid');
    }

    public function to(): string { return $this->to; }
    public function from(): string { return $this->from; }
    public function fromName(): string { return $this->from_name; }
    public function replyTo(): string { return $this->reply_to; }
    public function subject(): string { return $this->subject; }
    public function text(): string { return $this->text; }
    public function messageId(): string { return $this->message_id; }
    public function inReplyTo(): string { return $this->in_reply_to; }
    public function references(): array { return $this->references; }
    public function idempotencyKey(): string { return $this->idempotency_key; }

    public function headers(): array {
        $from = $this->from_name !== '' ? $this->encode($this->from_name) . ' <' . $this->from . '>' : '<' . $this->from . '>';
        $headers = array(
            'From: ' . $from,
            'Reply-To: <' . $this->reply_to . '>',
            'To: <' . $this->to . '>',
            'Subject: ' . $this->encode($this->subject),
            'Date: ' . date(DATE_RFC2822),
            'Message-ID: <' . $this->message_id . '>',
        );
        if ($this->in_reply_to !== '') $headers[] = 'In-Reply-To: <' . $this->in_reply_to . '>';
        if ($this->references) $headers[] = 'References: ' . implode(' ', array_map(function ($id) { return '<' . $id . '>'; }, $this->references));
        $headers[] = 'MIME-Version: 1.0';
        $headers[] = 'Content-Type: text/plain; charset=UTF-8';
        $headers[] = 'Content-Transfer-Encoding: 8bit';
        $headers[] = 'Auto-Submitted: no';
        return $headers;
    }

    private function email(string $value): string {
        $value = strtolower(trim($value));
        return filter_var($value, FILTER_VALIDATE_EMAIL) && strlen($value) <= 254 ? $value : '';
    }
    private function header(string $value, int $max): string {
        $value = trim((string)preg_replace('/[\r\n\x00-\x1F\x7F]+/u', ' ', $value));
        return function_exists('mb_substr') ? mb_substr($value, 0, $max, 'UTF-8') : substr($value, 0, $max);
    }
    private function normalizeMessageId(string $value): string {
        $value = trim($value, "<> \t\r\n");
        return $value !== '' && strlen($value) <= 512 && !preg_match('/[\r\n<>]/', $value) ? $value : '';
    }
    private function encode(string $value): string { return '=?UTF-8?B?' . base64_encode($value) . '?='; }
}
