<?php
/**
 * /rooms/includes/microsoft_graph_mailer.php
 *
 * Reusable Microsoft Graph email sender for PMS/DMS documents.
 *
 * No Composer required.
 * Uses cURL directly.
 */

require_once __DIR__ . '/../config/microsoft_graph.php';

if (!function_exists('mg_normalize_email_list')) {
    function mg_normalize_email_list($value): array
    {
        if (is_array($value)) {
            $raw = $value;
        } else {
            $raw = preg_split('/[;,]+/', (string)$value);
        }

        $emails = [];
        foreach ($raw as $email) {
            $email = trim((string)$email);
            if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $emails[] = $email;
            }
        }

        return array_values(array_unique($emails));
    }
}

if (!function_exists('mg_current_user_id')) {
    function mg_current_user_id(): ?int
    {
        foreach (['user_id', 'ss_user_id', 'id', 'uid', 'staffid'] as $key) {
            if (!empty($_SESSION[$key]) && (int)$_SESSION[$key] > 0) {
                return (int)$_SESSION[$key];
            }
        }
        return null;
    }
}

if (!function_exists('mg_request')) {
    function mg_request(string $method, string $url, array $headers = [], $body = null): array
    {
        if (!function_exists('curl_init')) {
            throw new RuntimeException('PHP cURL extension is required for Microsoft Graph email sending.');
        }

        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);

        if ($headers) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }

        if ($body !== null) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        }

        $response = curl_exec($ch);

        if ($response === false) {
            $error = curl_error($ch);
            curl_close($ch);
            throw new RuntimeException('Graph request failed: ' . $error);
        }

        $headerSize = (int)curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $statusCode = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        $rawHeaders = substr($response, 0, $headerSize);
        $rawBody = substr($response, $headerSize);
        curl_close($ch);

        return [
            'status' => $statusCode,
            'headers' => $rawHeaders,
            'body' => $rawBody,
        ];
    }
}

if (!function_exists('mg_get_access_token')) {
    function mg_get_access_token(): string
    {
        $tenantId = trim((string)MS_GRAPH_TENANT_ID);
        $clientId = trim((string)MS_GRAPH_CLIENT_ID);
        $clientSecret = trim((string)MS_GRAPH_CLIENT_SECRET);

        if ($tenantId === '' || $tenantId === 'PASTE_TENANT_ID_HERE') {
            throw new RuntimeException('Microsoft Graph Tenant ID is not configured.');
        }
        if ($clientId === '' || $clientId === 'PASTE_CLIENT_ID_HERE') {
            throw new RuntimeException('Microsoft Graph Client ID is not configured.');
        }
        if ($clientSecret === '' || $clientSecret === 'PASTE_CLIENT_SECRET_HERE') {
            throw new RuntimeException('Microsoft Graph Client Secret is not configured.');
        }

        $url = 'https://login.microsoftonline.com/' . rawurlencode($tenantId) . '/oauth2/v2.0/token';

        $postFields = http_build_query([
            'client_id' => $clientId,
            'client_secret' => $clientSecret,
            'scope' => 'https://graph.microsoft.com/.default',
            'grant_type' => 'client_credentials',
        ]);

        $resp = mg_request('POST', $url, [
            'Content-Type: application/x-www-form-urlencoded',
        ], $postFields);

        $json = json_decode($resp['body'], true);

        if ($resp['status'] < 200 || $resp['status'] >= 300) {
            $message = $json['error_description'] ?? $json['error'] ?? $resp['body'];
            throw new RuntimeException('Could not get Microsoft Graph access token: ' . $message);
        }

        $token = (string)($json['access_token'] ?? '');
        if ($token === '') {
            throw new RuntimeException('Microsoft Graph did not return an access token.');
        }

        return $token;
    }
}

if (!function_exists('mg_recipient_objects')) {
    function mg_recipient_objects(array $emails): array
    {
        $rows = [];
        foreach ($emails as $email) {
            $rows[] = [
                'emailAddress' => [
                    'address' => $email,
                ],
            ];
        }
        return $rows;
    }
}

if (!function_exists('mg_send_pdf_email')) {
    function mg_send_pdf_email(array $payload): array
    {
        $to = mg_normalize_email_list($payload['to'] ?? '');
        $cc = mg_normalize_email_list($payload['cc'] ?? '');
        $bcc = mg_normalize_email_list($payload['bcc'] ?? '');

        if (!$to) {
            throw new RuntimeException('Please enter at least one valid recipient email address.');
        }

        $subject = trim((string)($payload['subject'] ?? ''));
        if ($subject === '') {
            throw new RuntimeException('Email subject is required.');
        }

        $bodyText = (string)($payload['body'] ?? '');
        if (trim($bodyText) === '') {
            throw new RuntimeException('Email body is required.');
        }

        $attachmentPath = (string)($payload['attachment_path'] ?? '');
        $attachmentName = trim((string)($payload['attachment_name'] ?? 'document.pdf'));

        if ($attachmentPath === '' || !is_file($attachmentPath)) {
            throw new RuntimeException('PDF attachment was not found.');
        }

        $pdfData = file_get_contents($attachmentPath);
        if ($pdfData === false || $pdfData === '') {
            throw new RuntimeException('PDF attachment could not be read.');
        }

        $message = [
            'subject' => $subject,
            'body' => [
                'contentType' => 'HTML',
                'content' => nl2br(htmlspecialchars($bodyText, ENT_QUOTES, 'UTF-8')),
            ],
            'toRecipients' => mg_recipient_objects($to),
            'attachments' => [
                [
                    '@odata.type' => '#microsoft.graph.fileAttachment',
                    'name' => $attachmentName,
                    'contentType' => 'application/pdf',
                    'contentBytes' => base64_encode($pdfData),
                ],
            ],
        ];

        if ($cc) {
            $message['ccRecipients'] = mg_recipient_objects($cc);
        }

        if ($bcc) {
            $message['bccRecipients'] = mg_recipient_objects($bcc);
        }

        $payloadGraph = [
            'message' => $message,
            'saveToSentItems' => (bool)MS_GRAPH_SAVE_TO_SENT_ITEMS,
        ];

        $token = mg_get_access_token();

        $sender = trim((string)MS_GRAPH_SENDER_EMAIL);
        if ($sender === '') {
            throw new RuntimeException('Microsoft Graph sender email is not configured.');
        }

        $url = 'https://graph.microsoft.com/v1.0/users/' . rawurlencode($sender) . '/sendMail';

        $resp = mg_request('POST', $url, [
            'Authorization: Bearer ' . $token,
            'Content-Type: application/json',
        ], json_encode($payloadGraph, JSON_UNESCAPED_SLASHES));

        if ($resp['status'] < 200 || $resp['status'] >= 300) {
            $json = json_decode($resp['body'], true);
            $message = $json['error']['message'] ?? $resp['body'];
            throw new RuntimeException('Microsoft Graph sendMail failed with status ' . $resp['status'] . ': ' . $message);
        }

        return [
            'status_code' => $resp['status'],
            'message_id' => '',
            'to' => $to,
            'cc' => $cc,
            'bcc' => $bcc,
            'attachment_name' => $attachmentName,
        ];
    }
}

if (!function_exists('mg_log_booking_email')) {
    function mg_log_booking_email(PDO $pdo, array $data): void
    {
        $pdo->exec("
            CREATE TABLE IF NOT EXISTS booking_email_log (
                id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
                order_id INT UNSIGNED NOT NULL,
                email_type VARCHAR(80) NOT NULL,
                email_to TEXT NULL,
                email_cc TEXT NULL,
                email_bcc TEXT NULL,
                subject VARCHAR(255) NULL,
                body MEDIUMTEXT NULL,
                attachment_name VARCHAR(255) NULL,
                provider VARCHAR(40) NOT NULL DEFAULT 'microsoft_graph',
                provider_message_id VARCHAR(255) NULL,
                status VARCHAR(40) NOT NULL DEFAULT 'sent',
                error_message TEXT NULL,
                sent_by INT UNSIGNED NULL,
                sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                INDEX idx_booking_email_order (order_id),
                INDEX idx_booking_email_type (email_type),
                INDEX idx_booking_email_status (status)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        ");

        $stmt = $pdo->prepare("
            INSERT INTO booking_email_log
            (
                order_id,
                email_type,
                email_to,
                email_cc,
                email_bcc,
                subject,
                body,
                attachment_name,
                provider,
                provider_message_id,
                status,
                error_message,
                sent_by,
                sent_at
            )
            VALUES
            (
                :order_id,
                :email_type,
                :email_to,
                :email_cc,
                :email_bcc,
                :subject,
                :body,
                :attachment_name,
                :provider,
                :provider_message_id,
                :status,
                :error_message,
                :sent_by,
                NOW()
            )
        ");

        $stmt->execute([
            ':order_id' => (int)($data['order_id'] ?? 0),
            ':email_type' => (string)($data['email_type'] ?? 'document'),
            ':email_to' => (string)($data['email_to'] ?? ''),
            ':email_cc' => (string)($data['email_cc'] ?? ''),
            ':email_bcc' => (string)($data['email_bcc'] ?? ''),
            ':subject' => (string)($data['subject'] ?? ''),
            ':body' => (string)($data['body'] ?? ''),
            ':attachment_name' => (string)($data['attachment_name'] ?? ''),
            ':provider' => (string)($data['provider'] ?? 'microsoft_graph'),
            ':provider_message_id' => (string)($data['provider_message_id'] ?? ''),
            ':status' => (string)($data['status'] ?? 'sent'),
            ':error_message' => (string)($data['error_message'] ?? ''),
            ':sent_by' => !empty($data['sent_by']) ? (int)$data['sent_by'] : null,
        ]);
    }
}
