<?php

namespace App\Libraries;

use App\Models\EmailLogModel;
use CodeIgniter\Email\Email;
use Throwable;

/**
 * Real outbound email, same "per-tenant credentials from Settings, never
 * .env" pattern as HubtelService/WhatsAppService — every hotel has its
 * own mailbox/SMTP account, not a shared one baked into the codebase.
 *
 * Previously the only outbound channels in this app were SMS and
 * WhatsApp (see MessagingService's doc comment on why — no email
 * infrastructure existed). This doesn't touch that guest-messaging path
 * at all; it's a separate, narrower capability for staff-initiated sends
 * (e.g. FolioController's "Email Invoice") where SMS/WhatsApp templates
 * don't fit (a PDF attachment, not a short templated text).
 *
 * Same tolerance-of-failure as every other optional integration in this
 * app: an unconfigured or unreachable SMTP server never throws out of
 * send() into the caller's request — it's caught and reported via the
 * return value so a folio page, say, can still render with a flashed
 * error instead of a 500.
 */
class EmailService
{
    public function __construct(private readonly Settings $settings)
    {
    }

    public function isConfigured(): bool
    {
        return (bool) $this->settings->get('email.smtp_host');
    }

    /**
     * @param string $body HTML body
     * @param array{filename: string, content: string, mime: string}|null $attachment Raw PDF bytes, not a file path
     * @param int|null $guestId Logged to email_log for the guest's communication timeline — null for a
     *                          non-guest recipient (e.g. a corporate account statement).
     *
     * @return array{success: bool, error: ?string}
     */
    public function send(string $toEmail, string $subject, string $body, ?array $attachment = null, ?int $guestId = null): array
    {
        $host = $this->settings->get('email.smtp_host');

        if (! $host) {
            $error = 'Email is not configured for this hotel yet — set it up under Settings > Integrations.';
            (new EmailLogModel())->record($guestId, $toEmail, $subject, false, $error);

            return ['success' => false, 'error' => $error];
        }

        $fromEmail = $this->settings->get('email.from_address') ?: $host;
        $fromName  = $this->settings->get('email.from_name') ?: 'MaxYields PMS';

        $email = new Email([
            'protocol'   => 'smtp',
            'SMTPHost'   => $host,
            'SMTPPort'   => (int) ($this->settings->get('email.smtp_port') ?: 587),
            'SMTPUser'   => $this->settings->get('email.smtp_username') ?: '',
            'SMTPPass'   => $this->settings->get('email.smtp_password') ?: '',
            'SMTPCrypto' => $this->settings->get('email.smtp_encryption') ?: 'tls',
            'mailType'   => 'html',
            'fromEmail'  => $fromEmail,
            'fromName'   => $fromName,
        ]);

        $email->setFrom($fromEmail, $fromName);
        $email->setTo($toEmail);
        $email->setSubject($subject);
        $email->setMessage($body);

        if ($attachment !== null) {
            // Passing a non-empty $mime makes attach() treat $file as a raw
            // content buffer instead of a path to fopen() — no temp file
            // needed for a PDF generated in memory (see PdfService).
            $email->attach($attachment['content'], 'attachment', $attachment['filename'], $attachment['mime']);
        }

        try {
            $sent = $email->send(false);
        } catch (Throwable $e) {
            log_message('error', 'EmailService::send — ' . $e->getMessage());
            $error = 'Could not send email: ' . $e->getMessage();
            (new EmailLogModel())->record($guestId, $toEmail, $subject, false, $error);

            return ['success' => false, 'error' => $error];
        }

        if (! $sent) {
            log_message('error', 'EmailService::send — ' . $email->printDebugger(['headers']));
            $error = 'The mail server rejected the message. Check the SMTP settings under Settings > Integrations.';
            (new EmailLogModel())->record($guestId, $toEmail, $subject, false, $error);

            return ['success' => false, 'error' => $error];
        }

        (new EmailLogModel())->record($guestId, $toEmail, $subject, true, null);

        return ['success' => true, 'error' => null];
    }
}
