<?php
/**
 * Builds the acknowledgement and notification emails.
 *
 * @package SkyServers\Retragere
 */

declare(strict_types=1);

namespace SkyServers\Retragere\Core;

/**
 * Rendered from the snapshot captured when the declaration was submitted, so
 * a resend six months later reproduces the original document.
 */
final class EmailComposer
{
    /** @var array<string,mixed> */
    private $snapshot;

    /**
     * @param array<string,mixed> $snapshot
     */
    public function __construct(array $snapshot)
    {
        $this->snapshot = $snapshot;
    }

    /**
     * @return array{subject:string,html:string,text:string}
     */
    public function clientConfirmation(
        WithdrawalRequest $request,
        string $reference,
        string $submittedAtLocal,
        string $timezoneLabel,
        string $statusUrl
    ): array {
        $subject = 'Confirmare primire cerere de retragere - ' . $reference;

        $blocks   = [];
        $blocks[] = 'Am primit cererea dumneavoastră de retragere din contract, înregistrată la '
            . $submittedAtLocal . ' (' . $timezoneLabel . ').';
        $blocks[] = 'Cod de referință: ' . $reference;
        $blocks[] = "Conținutul declarației transmise:\n\n" . $request->declarationText();
        $blocks[] = 'Comerciant: ' . $this->identification();
        $blocks[] = 'Vom restitui sumele plătite în termen de cel mult '
            . (int) ($this->snapshot['refund_days'] ?? 14)
            . ' zile de la data prezentei confirmări. Pașii pentru returnarea produsului '
            . 'vă sunt comunicați de magazin la adresa de email indicată.';
        $blocks[] = ['text' => (string) ($this->snapshot['return_notice'] ?? ''), 'strong' => true];
        $blocks[] = (string) ($this->snapshot['legal_text'] ?? '');

        if ('' !== $statusUrl) {
            $blocks[] = 'Puteți urmări starea cererii aici: ' . $statusUrl;
        }

        return $this->render($subject, $blocks);
    }

    /**
     * @return array{subject:string,html:string,text:string}
     */
    public function storeNotification(
        WithdrawalRequest $request,
        string $reference,
        string $submittedAtLocal,
        string $timezoneLabel
    ): array {
        $subject = 'Cerere nouă de retragere din contract - ' . $reference;

        $blocks   = [];
        $blocks[] = 'A fost înregistrată o cerere de retragere din contract la '
            . $submittedAtLocal . ' (' . $timezoneLabel . ').';
        $blocks[] = 'Cod de referinta: ' . $reference;
        $blocks[] = 'Client: ' . $request->name() . ' - ' . $request->email();
        $blocks[] = 'Tip cerere: ' . $request->type();

        // Shown to the shop only. Tells the operator straight away whether the
        // refund can be reversed on the original method or whether a bank
        // account has to be requested from the customer.
        $payment = (string) ($this->snapshot['payment_method'] ?? '');
        if ('' !== trim($payment)) {
            $blocks[] = 'Metoda de plată a comenzii: ' . $payment;
        }

        $blocks[] = "Conținutul declarației transmise:\n\n" . $request->declarationText();
        $blocks[] = 'Termenul legal de restituire este de '
            . (int) ($this->snapshot['refund_days'] ?? 14)
            . ' zile de la primirea acestei cereri.';

        return $this->render($subject, $blocks);
    }

    /**
     * The message the shop chose is the point of this email. Everything else is
     * context, so it stays short.
     *
     * @return array{subject:string,html:string,text:string}
     */
    public function decision(
        WithdrawalRequest $request,
        string $reference,
        string $submittedAtLocal,
        string $timezoneLabel,
        string $outcome,
        string $message
    ): array {
        $approved = 'aprobata' === $outcome;

        $subject = $approved
            ? 'Cererea de retragere a fost aprobată - ' . $reference
            : 'Răspuns la cererea de retragere - ' . $reference;

        $blocks   = [];
        $blocks[] = $approved
            ? 'Cererea dumneavoastră de retragere din contract a fost aprobată.'
            : 'Am analizat cererea dumneavoastră de retragere din contract.';
        $blocks[] = 'Cod de referinta: ' . $reference;
        $blocks[] = 'Cerere transmisă la ' . $submittedAtLocal . ' (' . $timezoneLabel . ').';

        if ('' !== trim($message)) {
            $blocks[] = ['text' => $message, 'strong' => true];
        }

        $blocks[] = "Conținutul declarației transmise:\n\n" . $request->declarationText();
        $blocks[] = 'Comerciant: ' . $this->identification();

        return $this->render($subject, $blocks);
    }

    /**
     * A block is either a plain string or an array with a text key and an
     * optional strong flag. Emphasis applies to the HTML variant only: the
     * plain text version must stay readable, not littered with markup.
     *
     * @param array<int,mixed> $blocks
     *
     * @return array{subject:string,html:string,text:string}
     */
    private function render(string $subject, array $blocks): array
    {
        $normalised = [];

        foreach ($blocks as $block) {
            $content = is_array($block) ? (string) ($block['text'] ?? '') : (string) $block;

            if ('' === trim($content)) {
                continue;
            }

            $normalised[] = [
                'text'   => $content,
                'strong' => is_array($block) && !empty($block['strong']),
            ];
        }

        $textParts = [];
        $html      = '';

        foreach ($normalised as $block) {
            $textParts[] = $block['text'];

            $escaped = nl2br(htmlspecialchars($block['text'], ENT_QUOTES, 'UTF-8'));
            $html   .= $block['strong']
                ? '<p><strong>' . $escaped . '</strong></p>' . "\n"
                : '<p>' . $escaped . '</p>' . "\n";
        }

        return [
            'subject' => $subject,
            'html'    => $html,
            'text'    => implode("\n\n", $textParts),
        ];
    }

    private function identification(): string
    {
        $parts = [
            (string) ($this->snapshot['store_name'] ?? ''),
            'CUI ' . (string) ($this->snapshot['store_cui'] ?? ''),
            'Reg. Com. ' . (string) ($this->snapshot['store_reg'] ?? ''),
            (string) ($this->snapshot['store_address'] ?? ''),
            (string) ($this->snapshot['store_email'] ?? ''),
            (string) ($this->snapshot['store_phone'] ?? ''),
        ];

        return implode(', ', array_filter($parts, static function ($part) {
            return '' !== trim(str_replace(['CUI', 'Reg. Com.'], '', $part));
        }));
    }
}
