<?php

function getDialingCodeForCountry(?string $countryCode): ?string
{
    if (!$countryCode) {
        return null;
    }

    $map = [
        // Africa
        'GH' => '+233', // Ghana
        'NG' => '+234', // Nigeria
        'ZA' => '+27',  // South Africa
        'KE' => '+254', // Kenya
        'TZ' => '+255', // Tanzania
        'UG' => '+256', // Uganda
        'RW' => '+250', // Rwanda
        'CM' => '+237', // Cameroon
        'CI' => '+225', // CÃ´te d'Ivoire
        'SN' => '+221', // Senegal
        'ET' => '+251', // Ethiopia
        'ZM' => '+260', // Zambia
        'ZW' => '+263', // Zimbabwe
        'MW' => '+265', // Malawi

        // North America
        'US' => '+1',   // United States
        'CA' => '+1',   // Canada
        'MX' => '+52',  // Mexico

        // South America
        'BR' => '+55',  // Brazil
        'AR' => '+54',  // Argentina

        // Europe
        'GB' => '+44',  // United Kingdom
        'IE' => '+353', // Ireland
        'DE' => '+49',  // Germany
        'FR' => '+33',  // France
        'IT' => '+39',  // Italy
        'ES' => '+34',  // Spain
        'PT' => '+351', // Portugal
        'NL' => '+31',  // Netherlands
        'BE' => '+32',  // Belgium
        'CH' => '+41',  // Switzerland
        'AT' => '+43',  // Austria
        'SE' => '+46',  // Sweden
        'NO' => '+47',  // Norway
        'DK' => '+45',  // Denmark
        'PL' => '+48',  // Poland
        'RO' => '+40',  // Romania
        'CZ' => '+420', // Czech Republic
        'HU' => '+36',  // Hungary
        'GR' => '+30',  // Greece

        // Middle East & North Africa
        'AE' => '+971', // United Arab Emirates
        'SA' => '+966', // Saudi Arabia
        'EG' => '+20',  // Egypt
        'QA' => '+974', // Qatar
        'KW' => '+965', // Kuwait

        // Asia-Pacific
        'IN' => '+91',  // India
        'CN' => '+86',  // China
        'JP' => '+81',  // Japan
        'SG' => '+65',  // Singapore
        'MY' => '+60',  // Malaysia
        'PH' => '+63',  // Philippines
        'PK' => '+92',  // Pakistan
        'BD' => '+880', // Bangladesh
        'AU' => '+61',  // Australia
        'NZ' => '+64',  // New Zealand
    ];

    $key = strtoupper($countryCode);
    return $map[$key] ?? null;
}

function normalizeInternationalPhone(string $phone, ?string $countryCode = null, ?string $region = null): ?string
{
    $trimmed = preg_replace('/[^0-9+]/', '', $phone);
    if ($trimmed === '' || $trimmed === null) {
        return null;
    }

    if (strpos($trimmed, '+') === 0) {
        return $trimmed;
    }

    if (strpos($trimmed, '00') === 0) {
        return '+' . substr($trimmed, 2);
    }

    $dialCode = getDialingCodeForCountry($countryCode);

    if (!$dialCode && $region) {
        $region = strtolower($region);
        if ($region === 'usa') {
            $dialCode = '+1';
        } elseif ($region === 'europe') {
            $dialCode = '+44';
        } elseif ($region === 'africa') {
            $dialCode = '+233';
        }
    }

    if (!$dialCode) {
        return $trimmed;
    }

    if (strpos($trimmed, '0') === 0) {
        $trimmed = substr($trimmed, 1);
    }

    return $dialCode . $trimmed;
}

function mnotifySendQuickSms(array $recipients, string $message, ?string $senderId = null, array $options = [], array $logContext = []): bool
{
    $userId = null;
    if (isset($logContext['user_id']) && is_numeric($logContext['user_id'])) {
        $userId = (int) $logContext['user_id'];
    }

    if (!defined('MNOTIFY_SMS_ENABLED') || MNOTIFY_SMS_ENABLED !== true) {
        logNotificationEvent($userId, 'sms', 'mnotify', implode(',', (array) $recipients), null, $message, 'failed', 'SMS disabled by configuration', [
            'reason' => 'disabled',
            'log_context' => $logContext,
        ]);
        return false;
    }

    if (!defined('MNOTIFY_API_KEY') || !MNOTIFY_API_KEY) {
        logNotificationEvent($userId, 'sms', 'mnotify', implode(',', (array) $recipients), null, $message, 'failed', 'Missing MNOTIFY_API_KEY configuration', [
            'reason' => 'missing_api_key',
            'log_context' => $logContext,
        ]);
        return false;
    }

    $recipients = array_values(array_filter($recipients, static function ($value) {
        return is_string($value) && trim($value) !== '';
    }));

    if (empty($recipients) || trim($message) === '') {
        logNotificationEvent($userId, 'sms', 'mnotify', '', null, $message, 'failed', 'No valid SMS recipients or empty message', [
            'reason' => 'invalid_input',
            'log_context' => $logContext,
        ]);
        return false;
    }

    $baseUrl = defined('MNOTIFY_API_URL') ? MNOTIFY_API_URL : 'https://api.mnotify.com/api';
    $url = rtrim($baseUrl, '/') . '/sms/quick?key=' . urlencode(MNOTIFY_API_KEY);

    $payload = [
        'recipient' => $recipients,
        'sender' => $senderId ?: (defined('MNOTIFY_SMS_SENDER') ? MNOTIFY_SMS_SENDER : 'SmartThink'),
        'message' => $message,
    ];

    if (isset($options['is_schedule'])) {
        $payload['is_schedule'] = (bool) $options['is_schedule'];
    }

    if (!empty($options['schedule_date'])) {
        $payload['schedule_date'] = $options['schedule_date'];
    }

    if (!empty($options['sms_type'])) {
        $payload['sms_type'] = $options['sms_type'];
    }

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

    $response = curl_exec($ch);
    if ($response === false) {
        $error = curl_error($ch);
        error_log('mNotify SMS error: ' . $error);
        curl_close($ch);

        logNotificationEvent($userId, 'sms', 'mnotify', implode(',', $recipients), null, $message, 'failed', $error, [
            'reason' => 'curl_error',
            'payload' => $payload,
            'log_context' => $logContext,
        ]);
        return false;
    }

    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode >= 200 && $httpCode < 300) {
        logNotificationEvent($userId, 'sms', 'mnotify', implode(',', $recipients), null, $message, 'sent', null, [
            'http_code' => $httpCode,
            'response' => $response,
            'payload' => $payload,
            'log_context' => $logContext,
        ]);
        return true;
    }

    error_log('mNotify SMS HTTP ' . $httpCode . ' response: ' . $response);

    logNotificationEvent($userId, 'sms', 'mnotify', implode(',', $recipients), null, $message, 'failed', 'HTTP ' . $httpCode . ' response from mNotify', [
        'http_code' => $httpCode,
        'response' => $response,
        'payload' => $payload,
        'log_context' => $logContext,
    ]);

    return false;
}

function logNotificationEvent(
    ?int $userId,
    string $channel,
    string $provider,
    string $recipient,
    ?string $subject,
    ?string $message,
    string $status,
    ?string $errorMessage = null,
    array $meta = []
): void {
    try {
        $db = Database::getInstance();
        $db->insert('notification_logs', [
            'user_id' => $userId,
            'channel' => $channel,
            'provider' => $provider,
            'recipient' => $recipient,
            'subject' => $subject,
            'message' => $message !== null ? substr($message, 0, 1000) : null,
            'status' => $status,
            'error_message' => $errorMessage,
            'meta' => !empty($meta) ? json_encode($meta) : null,
            'created_at' => formatDate(),
        ]);
    } catch (Exception $e) {
        error_log('Notification log insert failed: ' . $e->getMessage());
    }
}

function sendUserWelcomeNotification(int $userId, ?string $plainPassword = null): void
{
    $db = Database::getInstance();
    $user = $db->get('SELECT * FROM users WHERE id = ?', [$userId]);

    if (!$user) {
        return;
    }

    $fullName = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? ''));
    $displayName = $fullName !== '' ? $fullName : ($user['username'] ?? 'User');

    $subject = 'Welcome to SmartThink LMS';
    $loginUrl = APP_URL . '/lms/login.php';

    $emailBody = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
        '<p>Welcome to <strong>SmartThink</strong>, your global learning platform.</p>' .
        '<p>Your account has been created successfully with the following details:</p>' .
        '<p><strong>Username:</strong> ' . htmlspecialchars($user['username'] ?? '', ENT_QUOTES, 'UTF-8') . '</p>';

    if ($plainPassword !== null && $plainPassword !== '') {
        $emailBody .= '<p><strong>Temporary password:</strong> ' . htmlspecialchars($plainPassword, ENT_QUOTES, 'UTF-8') . '</p>';
    }

    $emailBody .= '<p>You can log in anytime at: <a href="' . htmlspecialchars($loginUrl, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($loginUrl, ENT_QUOTES, 'UTF-8') . '</a></p>' .
        '<p>For your security, please change your password after your first login.</p>' .
        '<p>Happy learning!<br>SmartThink Team</p>';

    if (!empty($user['email'])) {
        $sent = sendEmail($user['email'], $subject, $emailBody);

        logNotificationEvent(
            (int) $user['id'],
            'email',
            'smtp',
            $user['email'],
            $subject,
            strip_tags($emailBody),
            $sent ? 'sent' : 'failed',
            $sent ? null : 'sendEmail returned false',
            []
        );
    }

    if (!empty($user['phone'])) {
        $normalized = normalizeInternationalPhone(
            $user['phone'],
            $user['country'] ?? null,
            $user['region'] ?? null
        );

        if ($normalized) {
            $smsMessage = 'Welcome to SmartThink, ' . $displayName . '. Username: ' . ($user['username'] ?? '');

            if ($plainPassword !== null && $plainPassword !== '') {
                $smsMessage .= ' Temp password: ' . $plainPassword;
            }

            $smsMessage .= ' Login: ' . $loginUrl . ' Please change your password after first login.';

            mnotifySendQuickSms([
                $normalized,
            ], $smsMessage, null, [], [
                'user_id' => (int) $user['id'],
                'type' => 'user_welcome',
            ]);
        }
    }
}

function sendEnrollmentInvoice(int $enrollmentId, string $gateway, array $gatewayData = []): void
{
    $db = Database::getInstance();

    $enrollment = $db->get('SELECT * FROM course_enrollments WHERE id = ?', [$enrollmentId]);
    if (!$enrollment) {
        return;
    }

    $course = $db->get('SELECT * FROM courses WHERE id = ?', [$enrollment['course_id']]);
    $user = $db->get('SELECT * FROM users WHERE id = ?', [$enrollment['student_id']]);

    if (!$user || empty($user['email'])) {
        return;
    }

    $fullName = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? ''));
    $displayName = $fullName !== '' ? $fullName : ($user['username'] ?? 'Student');

    $invoiceNumber = 'INV-' . str_pad((string)$enrollment['id'], 6, '0', STR_PAD_LEFT);
    $amount = (float)($enrollment['payment_amount'] ?? 0.0);
    $currency = $enrollment['currency'] ?? ($course['currency'] ?? 'USD');
    $courseTitle = $course['title'] ?? 'Course';
    $paymentDate = !empty($enrollment['updated_at']) ? $enrollment['updated_at'] : formatDate();
    $paymentId = $enrollment['payment_id'] ?? ($gatewayData['reference'] ?? ($gatewayData['transaction_ref'] ?? '')); 

    $subject = 'Payment Invoice - ' . $courseTitle;

    $emailBody = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
        '<p>Thank you for your payment. Below is your invoice for the course enrollment.</p>' .
        '<h3>Invoice Details</h3>' .
        '<p><strong>Invoice Number:</strong> ' . htmlspecialchars($invoiceNumber, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Course:</strong> ' . htmlspecialchars($courseTitle, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Amount Paid:</strong> ' . htmlspecialchars(number_format($amount, 2), ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Payment Gateway:</strong> ' . htmlspecialchars(strtoupper($gateway), ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Payment Reference:</strong> ' . htmlspecialchars($paymentId, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Payment Date:</strong> ' . htmlspecialchars($paymentDate, ENT_QUOTES, 'UTF-8') . '</p>' .
        '<p>Your enrollment has been activated. You can access your course here: ' .
        '<a href="' . htmlspecialchars(APP_URL . '/lms/courses.php?course_id=' . (int)$course['id'], ENT_QUOTES, 'UTF-8') . '">' .
        htmlspecialchars($courseTitle, ENT_QUOTES, 'UTF-8') . '</a></p>' .
        '<p>If you have any questions about this invoice, please reply to this email.</p>' .
        '<p>Best regards,<br>SmartThink Billing</p>';

    // Generate a simple PDF invoice and attach it
    $attachmentPath = null;
    try {
        $dir = rtrim(UPLOAD_PATH, '\\/') . DIRECTORY_SEPARATOR . 'invoices';
        if (!is_dir($dir)) {
            @mkdir($dir, 0755, true);
        }

        $filePath = $dir . DIRECTORY_SEPARATOR . $invoiceNumber . '.pdf';
        $pdfText = "Invoice Number: {$invoiceNumber}\n" .
            "Course: {$courseTitle}\n" .
            "Student: {$displayName}\n" .
            "Amount Paid: " . number_format($amount, 2) . " {$currency}\n" .
            "Payment Gateway: " . strtoupper($gateway) . "\n" .
            "Payment Reference: {$paymentId}\n" .
            "Payment Date: {$paymentDate}\n" .
            "\nThank you for your enrollment with SmartThink.";

        if (generateSimplePdfInvoice($filePath, $pdfText)) {
            $attachmentPath = $filePath;
        }
    } catch (Exception $e) {
        $attachmentPath = null;
    }

    $attachments = [];
    if ($attachmentPath && is_readable($attachmentPath)) {
        $attachments[] = [
            'path' => $attachmentPath,
            'filename' => $invoiceNumber . '.pdf',
            'mime' => 'application/pdf',
        ];
    }

    $sent = sendEmailWithAttachment($user['email'], $subject, $emailBody, $attachments);

    logNotificationEvent(
        (int)$user['id'],
        'email',
        'smtp',
        $user['email'],
        $subject,
        strip_tags($emailBody),
        $sent ? 'sent' : 'failed',
        $sent ? null : 'sendEmail returned false',
        [
            'type' => 'enrollment_invoice',
            'enrollment_id' => $enrollmentId,
            'gateway' => $gateway,
            'gateway_data' => $gatewayData,
        ]
    );
}

function generateSimplePdfInvoice(string $filePath, string $text): bool
{
    // Escape text for PDF
    $escaped = str_replace(['\\', '(', ')', "\r", "\n"], ['\\\\', '\\(', '\\)', ' ', ' '], $text);

    $objects = [];

    // 1: Catalog
    $objects[] = "1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n";

    // 2: Pages
    $objects[] = "2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n";

    // 3: Page
    $objects[] = "3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>\nendobj\n";

    // 4: Contents
    $contentStream = "BT\n/F1 12 Tf\n72 720 Td\n(" . $escaped . ") Tj\nET";
    $objects[] = "4 0 obj\n<< /Length " . strlen($contentStream) . " >>\nstream\n" . $contentStream . "\nendstream\nendobj\n";

    // 5: Font
    $objects[] = "5 0 obj\n<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>\nendobj\n";

    $pdf = "%PDF-1.4\n";
    $offsets = [];

    foreach ($objects as $index => $obj) {
        $objNum = $index + 1;
        $offsets[$objNum] = strlen($pdf);
        $pdf .= $obj;
    }

    $xrefPos = strlen($pdf);
    $count = count($objects) + 1; // include object 0

    $pdf .= "xref\n0 {$count}\n";
    $pdf .= sprintf("%010d 65535 f \n", 0);
    for ($i = 1; $i <= count($objects); $i++) {
        $pdf .= sprintf("%010d 00000 n \n", $offsets[$i]);
    }

    $pdf .= "trailer\n<< /Size {$count} /Root 1 0 R >>\nstartxref\n" . $xrefPos . "\n%%EOF";

    return file_put_contents($filePath, $pdf) !== false;
}

function sendInstallmentReminder(int $installmentId): void
{
    $db = Database::getInstance();

    $row = $db->get(
        'SELECT ei.*, ce.course_id, u.email, u.first_name, u.last_name, u.phone, u.country, u.region, c.title AS course_title
         FROM enrollment_installments ei
         JOIN course_enrollments ce ON ei.enrollment_id = ce.id
         JOIN users u ON ce.student_id = u.id
         JOIN courses c ON ce.course_id = c.id
         WHERE ei.id = ?',
        [$installmentId]
    );

    if (!$row || empty($row['email'])) {
        return;
    }

    $fullName = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? ''));
    $displayName = $fullName !== '' ? $fullName : ($row['email'] ?? 'Student');

    $dueDate = !empty($row['due_date']) ? $row['due_date'] : null;
    $dueFormatted = $dueDate ? date('Y-m-d H:i', strtotime($dueDate)) : '';

    $daysLeft = null;
    if ($dueDate) {
        $secondsDiff = strtotime($dueDate) - time();
        $daysLeft = (int) floor($secondsDiff / 86400);
    }

    $amount = (float)($row['amount'] ?? 0.0);
    $currency = $row['currency'] ?? 'USD';
    $courseTitle = $row['course_title'] ?? 'Course';

    $subjectBase = 'Upcoming installment payment due - ' . $courseTitle;
    if ($daysLeft !== null && $daysLeft >= 0) {
        $subject = 'Installment due in ' . $daysLeft . ' day' . ($daysLeft === 1 ? '' : 's') . ' - ' . $courseTitle;
    } else {
        $subject = $subjectBase;
    }

    $emailBody = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
        '<p>This is a reminder of your upcoming installment payment for the course <strong>' . htmlspecialchars($courseTitle, ENT_QUOTES, 'UTF-8') . '</strong>.</p>' .
        '<p><strong>Amount:</strong> ' . htmlspecialchars(number_format($amount, 2), ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Due date:</strong> ' . htmlspecialchars($dueFormatted, ENT_QUOTES, 'UTF-8') . '</p>' .
        '<p>You can log in to your SmartThink account to complete this installment payment. If you miss this payment, your account access may be suspended until an administrator reactivates it.</p>' .
        '<p>Best regards,<br>SmartThink Billing</p>';

    $sent = sendEmail($row['email'], $subject, $emailBody);

    logNotificationEvent(
        (int)($row['student_id'] ?? 0),
        'email',
        'smtp',
        $row['email'],
        $subject,
        strip_tags($emailBody),
        $sent ? 'sent' : 'failed',
        $sent ? null : 'sendEmail returned false',
        [
            'type' => 'installment_reminder',
            'enrollment_id' => (int)($row['enrollment_id'] ?? 0),
            'installment_id' => $installmentId,
        ]
    );

    // WhatsApp reminder (if phone is available and WhatsApp integration is configured)
    if (!empty($row['phone'])) {
        $normalized = normalizeInternationalPhone(
            $row['phone'],
            $row['country'] ?? null,
            $row['region'] ?? null
        );

        if ($normalized) {
            $waMessage = 'Reminder: Your installment payment for "' . $courseTitle . '" of ' .
                $currency . ' ' . number_format($amount, 2) . ' is due on ' . $dueFormatted .
                '. Please log in to your SmartThink dashboard to complete this payment.';

            try {
                if (!class_exists('WhatsApp') && file_exists(__DIR__ . '/../../classes/WhatsApp.php')) {
                    require_once __DIR__ . '/../../classes/WhatsApp.php';
                }

                if (class_exists('WhatsApp')) {
                    $wa = new WhatsApp();
                    $waResult = $wa->sendTextMessage($normalized, $waMessage);

                    $waSuccess = is_array($waResult) && !empty($waResult['success']);

                    logNotificationEvent(
                        (int)($row['student_id'] ?? 0),
                        'whatsapp',
                        'whatsapp',
                        $normalized,
                        null,
                        $waMessage,
                        $waSuccess ? 'sent' : 'failed',
                        $waSuccess ? null : json_encode($waResult),
                        [
                            'type' => 'installment_reminder',
                            'enrollment_id' => (int)($row['enrollment_id'] ?? 0),
                            'installment_id' => $installmentId,
                        ]
                    );
                }
            } catch (Exception $e) {
                logNotificationEvent(
                    (int)($row['student_id'] ?? 0),
                    'whatsapp',
                    'whatsapp',
                    $normalized,
                    null,
                    $waMessage,
                    'failed',
                    $e->getMessage(),
                    [
                        'type' => 'installment_reminder',
                        'enrollment_id' => (int)($row['enrollment_id'] ?? 0),
                        'installment_id' => $installmentId,
                    ]
                );
            }
        }
    }
}

function sendAppointmentRequestNotifications(int $appointmentId): void
{
    $db = Database::getInstance();

    $appt = $db->get('SELECT * FROM appointments WHERE id = ?', [$appointmentId]);
    if (!$appt) {
        return;
    }

    $userId = isset($appt['user_id']) ? (int)$appt['user_id'] : null;
    $name = trim($appt['name'] ?? '');
    $email = trim($appt['email'] ?? '');
    $topic = $appt['topic'] ?? 'Appointment';
    $preferred = !empty($appt['preferred_datetime']) ? date('Y-m-d H:i', strtotime($appt['preferred_datetime'])) : null;
    $timezone = $appt['timezone'] ?? null;

    $displayName = $name !== '' ? $name : ($email !== '' ? $email : 'Student');

    if ($email !== '') {
        $subject = 'Appointment request received - SmartThink';

        $body = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
            '<p>We have received your appointment request with SmartThink.</p>' .
            '<p><strong>Topic:</strong> ' . htmlspecialchars($topic, ENT_QUOTES, 'UTF-8') . '</p>';

        if ($preferred) {
            $body .= '<p><strong>Preferred time:</strong> ' . htmlspecialchars($preferred, ENT_QUOTES, 'UTF-8');
            if ($timezone) {
                $body .= ' (' . htmlspecialchars($timezone, ENT_QUOTES, 'UTF-8') . ')';
            }
            $body .= '</p>';
        }

        $body .= '<p>Our team will review your request and send you a Zoom meeting link once the appointment is scheduled.</p>' .
            '<p>Best regards,<br>SmartThink Team</p>';

        $sent = sendEmail($email, $subject, $body);

        logNotificationEvent(
            $userId,
            'email',
            'smtp',
            $email,
            $subject,
            strip_tags($body),
            $sent ? 'sent' : 'failed',
            $sent ? null : 'sendEmail returned false',
            [
                'type' => 'appointment_request_client',
                'appointment_id' => $appointmentId,
            ]
        );
    }

    if (defined('SMTP_FROM_EMAIL') && SMTP_FROM_EMAIL) {
        $adminEmail = SMTP_FROM_EMAIL;
        $subjectAdmin = 'New appointment request - ' . $topic;

        $adminBody = '<p>A new appointment request has been submitted.</p>' .
            '<p><strong>Name:</strong> ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . '<br>' .
            '<strong>Email:</strong> ' . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . '<br>' .
            (!empty($appt['phone']) ? '<strong>Phone:</strong> ' . htmlspecialchars($appt['phone'], ENT_QUOTES, 'UTF-8') . '<br>' : '') .
            '<strong>Topic:</strong> ' . htmlspecialchars($topic, ENT_QUOTES, 'UTF-8') . '</p>';

        if ($preferred) {
            $adminBody .= '<p><strong>Preferred time:</strong> ' . htmlspecialchars($preferred, ENT_QUOTES, 'UTF-8');
            if ($timezone) {
                $adminBody .= ' (' . htmlspecialchars($timezone, ENT_QUOTES, 'UTF-8') . ')';
            }
            $adminBody .= '</p>';
        }

        $adminBody .= '<p>You can manage this appointment here: ' .
            '<a href="' . htmlspecialchars(APP_URL . '/cms/appointments.php', ENT_QUOTES, 'UTF-8') . '">' .
            htmlspecialchars(APP_URL . '/cms/appointments.php', ENT_QUOTES, 'UTF-8') . '</a></p>';

        $sentAdmin = sendEmail($adminEmail, $subjectAdmin, $adminBody);

        logNotificationEvent(
            $userId,
            'email',
            'smtp',
            $adminEmail,
            $subjectAdmin,
            strip_tags($adminBody),
            $sentAdmin ? 'sent' : 'failed',
            $sentAdmin ? null : 'sendEmail returned false',
            [
                'type' => 'appointment_request_admin',
                'appointment_id' => $appointmentId,
            ]
        );
    }
}

function sendAppointmentScheduledNotification(int $appointmentId): void
{
    $db = Database::getInstance();

    $appt = $db->get('SELECT * FROM appointments WHERE id = ?', [$appointmentId]);
    if (!$appt) {
        return;
    }

    $userId = isset($appt['user_id']) ? (int)$appt['user_id'] : null;
    $name = trim($appt['name'] ?? '');
    $email = trim($appt['email'] ?? '');
    $topic = $appt['topic'] ?? 'Appointment';
    $zoomUrl = $appt['zoom_join_url'] ?? null;
    $zoomStart = !empty($appt['zoom_start_time']) ? date('Y-m-d H:i', strtotime($appt['zoom_start_time'])) : null;
    $timezone = $appt['timezone'] ?? null;

    if ($email === '' || !$zoomUrl) {
        return;
    }

    $displayName = $name !== '' ? $name : $email;

    $subject = 'Your SmartThink appointment is scheduled';

    $body = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
        '<p>Your appointment with SmartThink has been scheduled.</p>' .
        '<p><strong>Topic:</strong> ' . htmlspecialchars($topic, ENT_QUOTES, 'UTF-8') . '</p>';

    if ($zoomStart) {
        $body .= '<p><strong>Date &amp; time:</strong> ' . htmlspecialchars($zoomStart, ENT_QUOTES, 'UTF-8');
        if ($timezone) {
            $body .= ' (' . htmlspecialchars($timezone, ENT_QUOTES, 'UTF-8') . ')';
        }
        $body .= '</p>';
    }

    $body .= '<p><strong>Join Zoom:</strong> ' .
        '<a href="' . htmlspecialchars($zoomUrl, ENT_QUOTES, 'UTF-8') . '">' .
        htmlspecialchars($zoomUrl, ENT_QUOTES, 'UTF-8') . '</a></p>' .
        '<p>Please join a few minutes before the scheduled time. If you need to reschedule, reply to this email.</p>' .
        '<p>Best regards,<br>SmartThink Team</p>';

    $sent = sendEmail($email, $subject, $body);

    logNotificationEvent(
        $userId,
        'email',
        'smtp',
        $email,
        $subject,
        strip_tags($body),
        $sent ? 'sent' : 'failed',
        $sent ? null : 'sendEmail returned false',
        [
            'type' => 'appointment_scheduled',
            'appointment_id' => $appointmentId,
        ]
    );
}

function sendAppointmentReminderNotification(int $appointmentId): void
{
    $db = Database::getInstance();

    $appt = $db->get('SELECT * FROM appointments WHERE id = ?', [$appointmentId]);
    if (!$appt) {
        return;
    }

    $userId = isset($appt['user_id']) ? (int)$appt['user_id'] : null;
    $name = trim($appt['name'] ?? '');
    $email = trim($appt['email'] ?? '');
    $topic = $appt['topic'] ?? 'Appointment';
    $zoomUrl = $appt['zoom_join_url'] ?? null;
    $zoomStart = !empty($appt['zoom_start_time']) ? date('Y-m-d H:i', strtotime($appt['zoom_start_time'])) : null;
    $timezone = $appt['timezone'] ?? null;

    if ($email === '' || !$zoomStart) {
        return;
    }

    $displayName = $name !== '' ? $name : $email;

    $subject = 'Reminder: your SmartThink appointment starts soon';

    $body = '<p>Hi ' . htmlspecialchars($displayName, ENT_QUOTES, 'UTF-8') . ',</p>' .
        '<p>This is a reminder that your appointment with SmartThink is starting soon (in about an hour).</p>' .
        '<p><strong>Topic:</strong> ' . htmlspecialchars($topic, ENT_QUOTES, 'UTF-8') . '</p>' .
        '<p><strong>Date &amp; time:</strong> ' . htmlspecialchars($zoomStart, ENT_QUOTES, 'UTF-8');

    if ($timezone) {
        $body .= ' (' . htmlspecialchars($timezone, ENT_QUOTES, 'UTF-8') . ')';
    }

    $body .= '</p>';

    if ($zoomUrl) {
        $body .= '<p><strong>Join Zoom:</strong> ' .
            '<a href="' . htmlspecialchars($zoomUrl, ENT_QUOTES, 'UTF-8') . '">' .
            htmlspecialchars($zoomUrl, ENT_QUOTES, 'UTF-8') . '</a></p>';
    }

    $body .= '<p>Please ensure your internet connection and audio/video are working before the call.</p>' .
        '<p>Best regards,<br>SmartThink Team</p>';

    $sent = sendEmail($email, $subject, $body);

    logNotificationEvent(
        $userId,
        'email',
        'smtp',
        $email,
        $subject,
        strip_tags($body),
        $sent ? 'sent' : 'failed',
        $sent ? null : 'sendEmail returned false',
        [
            'type' => 'appointment_reminder',
            'appointment_id' => $appointmentId,
        ]
    );
}
