<?php

declare(strict_types=1);

final class MicFormNotificationDispatcher
{
    public function __construct(
        private readonly MicFormRepository $forms,
        private readonly MicFormSubmissionRepository $submissions,
        private readonly MicFormNotificationFailureRepository $failures,
        private readonly NotificationEmailsRepository $notificationEmails,
        private readonly MyronMailSettingsRepository $mailSettings,
        private readonly MicFormNotificationBody $bodyBuilder,
    ) {
    }

    public function dispatch(string $submissionId): MailDispatchResult
    {
        $submission = $this->submissions->findById($submissionId);
        if ($submission === null) {
            return MailDispatchResult::failed('smtp', 'submission_not_found');
        }
        $form = $this->forms->findById((string) ($submission['form_id'] ?? ''));
        if ($form === null) {
            return MailDispatchResult::failed('smtp', 'form_not_found');
        }

        if (trim((string) ($form['notification_email_id'] ?? '')) === 'none') {
            return MailDispatchResult::ok('store-only');
        }

        $recipient = $this->notificationEmails->resolveRecipientForForm($form);
        if ($recipient === null) {
            $this->failures->recordFailure($submissionId, (string) $form['id'], '', 'no_recipient');
            return MailDispatchResult::failed('smtp', 'no_recipient');
        }

        $settings = $this->mailSettings->getSettings();
        if (!is_array($settings)) {
            $this->failures->recordFailure($submissionId, (string) $form['id'], (string) $recipient['address'], 'mail_settings_missing');
            return MailDispatchResult::failed('smtp', 'mail_settings_missing');
        }

        $envelope = $this->bodyBuilder->build($form, $submission, (string) $recipient['address'], $settings);
        $started = microtime(true);
        try {
            $result = myronMailTransportRegistry()->activeTransport()->send($envelope);
        } catch (Throwable $exception) {
            $result = MailDispatchResult::failed('smtp', $exception->getMessage());
        }
        if ((microtime(true) - $started) > 5.0 && $result->ok) {
            $result = MailDispatchResult::failed('smtp', 'timeout');
        }
        if (!$result->ok) {
            $this->failures->recordFailure($submissionId, (string) $form['id'], (string) $recipient['address'], $result->error ?? 'dispatch_failed');
        }
        return $result;
    }
}
