<?php
/**
 * Sends the acknowledgement and the store notification.
 *
 * @package SkyServers\Retragere
 */

declare(strict_types=1);

namespace SkyServers\Retragere\Wp;

use SkyServers\Retragere\Core\EmailComposer;

/**
 * The plugin never configures SMTP. wp_mail() is the universal contract and
 * whatever the site uses to route it applies automatically.
 */
final class Mailer
{
    public const HOOK_RETRY = 'ssrc_retry_email';

    /** @var array<int,int> Backoff in seconds, indexed by attempt number. */
    private const BACKOFF = [1 => 300, 2 => 1800, 3 => 7200];

    public static function send(int $id): void
    {
        if (self::hasWooEmails()) {
            self::sendViaWoo($id);

            return;
        }

        self::sendDirect($id);
    }

    public static function hasWooEmails(): bool
    {
        return function_exists('WC')
            && null !== \SkyServers\Retragere\Wc\Emails\Registrar::get('SSRC_Customer_Email');
    }

    private static function sendViaWoo(int $id): void
    {
        $failed = false;

        $customer = \SkyServers\Retragere\Wc\Emails\Registrar::get('SSRC_Customer_Email');
        if (null !== $customer && '' === (string) get_post_meta($id, Repository::META_MAIL_CLIENT, true)) {
            if ($customer->dispatch($id)) {
                Repository::markEmailSent($id, 'client', gmdate('Y-m-d H:i:s'));
            } else {
                $failed = true;
            }
        }

        $store = \SkyServers\Retragere\Wc\Emails\Registrar::get('SSRC_Store_Email');
        if (null !== $store && '' === (string) get_post_meta($id, Repository::META_MAIL_ADMIN, true)) {
            if ($store->dispatch($id)) {
                Repository::markEmailSent($id, 'admin', gmdate('Y-m-d H:i:s'));
            } else {
                $failed = true;
            }
        }

        if ($failed) {
            self::scheduleRetry($id);
        }
    }

    /**
     * Fallback for installs without WooCommerce.
     */
    private static function sendDirect(int $id): void
    {
        $request = Repository::request($id);

        if (null === $request) {
            return;
        }

        $snapshot = Repository::snapshot($id);
        $composer = new EmailComposer($snapshot);

        $post      = get_post($id);
        $gmt       = $post ? (string) $post->post_date_gmt : gmdate('Y-m-d H:i:s');
        $localTime = wp_date('d.m.Y H:i:s', (int) strtotime($gmt . ' UTC'));
        $tzLabel   = wp_timezone_string();
        $reference = Repository::reference($id);

        $failed = false;

        if ('' === (string) get_post_meta($id, Repository::META_MAIL_CLIENT, true)) {
            $mail = $composer->clientConfirmation(
                $request,
                $reference,
                (string) $localTime,
                $tzLabel,
                ''
            );

            if (self::deliver($id, $request->email(), $mail)) {
                Repository::markEmailSent($id, 'client', gmdate('Y-m-d H:i:s'));
            } else {
                $failed = true;
            }
        }

        if ('' === (string) get_post_meta($id, Repository::META_MAIL_ADMIN, true)) {
            $mail = $composer->storeNotification($request, $reference, (string) $localTime, $tzLabel);

            if (self::deliver($id, (string) Settings::get('notify_recipients'), $mail)) {
                Repository::markEmailSent($id, 'admin', gmdate('Y-m-d H:i:s'));
            } else {
                $failed = true;
            }
        }

        if ($failed) {
            self::scheduleRetry($id);
        }
    }

    public static function onRetry(int $id): void
    {
        self::send($id);
    }

    private static function scheduleRetry(int $id): void
    {
        $attempt = Repository::bumpAttempts($id);

        if (!isset(self::BACKOFF[$attempt])) {
            return;
        }

        wp_schedule_single_event(time() + self::BACKOFF[$attempt], self::HOOK_RETRY, [$id]);
    }

    /**
     * @param array{subject:string,html:string,text:string} $mail
     */
    private static function deliver(int $id, string $to, array $mail): bool
    {
        if ('' === trim($to)) {
            return false;
        }

        $text      = $mail['text'];
        $transport = '';

        $capture = static function ($phpmailer) use ($text, &$transport) {
            $phpmailer->AltBody = $text;
            $transport          = (string) $phpmailer->Mailer;

            if ('' !== (string) $phpmailer->Host) {
                $transport .= ':' . (string) $phpmailer->Host;
            }
        };

        add_action('phpmailer_init', $capture, 99);

        $sent = wp_mail(
            $to,
            $mail['subject'],
            $mail['html'],
            ['Content-Type: text/html; charset=UTF-8']
        );

        remove_action('phpmailer_init', $capture, 99);

        if ('' !== $transport) {
            Repository::setTransport($id, $transport);
        }

        return (bool) $sent;
    }

    /**
     * True when something already routes wp_mail through a real transport.
     */
    public static function isConfigured(): bool
    {
        return (bool) has_action('phpmailer_init');
    }
}
