<?php

require_once __DIR__ . '/database.php';
require_once __DIR__ . '/password_reset.php';
require_once __DIR__ . '/invoice_data.php';

if (!function_exists('conventa_invoice_notifications_available')) {
    function conventa_invoice_notifications_available(PDO $pdo): bool
    {
        static $available = null;

        if ($available !== null) {
            return $available;
        }

        $stmt = $pdo->query("SHOW COLUMNS FROM users");
        $columns = [];
        foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $field = strtolower((string) ($row['Field'] ?? ''));
            if ($field !== '') {
                $columns[$field] = true;
            }
        }

        foreach (['notification_frequency', 'notification_last_sent_at'] as $requiredColumn) {
            if (!isset($columns[$requiredColumn])) {
                $available = false;
                return $available;
            }
        }

        try {
            $pdo->query('SELECT 1 FROM invoice_notification_log LIMIT 1');
        } catch (Throwable $e) {
            $available = false;
            return $available;
        }

        $available = true;
        return $available;
    }
}

if (!function_exists('conventa_invoice_notification_frequency_options')) {
    function conventa_invoice_notification_frequency_options(): array
    {
        return [
            'immediate' => 'Immediate',
            'daily' => 'Daily',
            'weekly' => 'Weekly',
            'off' => 'Off',
        ];
    }
}

if (!function_exists('conventa_normalize_invoice_notification_frequency')) {
    function conventa_normalize_invoice_notification_frequency(?string $value): string
    {
        $value = strtolower(trim((string) $value));
        $options = conventa_invoice_notification_frequency_options();

        return isset($options[$value]) ? $value : 'immediate';
    }
}

if (!function_exists('conventa_invoice_status_is_blank')) {
    function conventa_invoice_status_is_blank(?string $approval): bool
    {
        $approval = preg_replace('/<\s*br\s*\/?>/i', '', (string) $approval);

        return trim(strip_tags((string) $approval)) === '';
    }
}

if (!function_exists('conventa_invoice_notification_is_due')) {
    function conventa_invoice_notification_is_due(string $frequency, ?string $lastSentAt, ?DateTimeImmutable $now = null): bool
    {
        $frequency = conventa_normalize_invoice_notification_frequency($frequency);

        if ($frequency === 'off') {
            return false;
        }

        if ($frequency === 'immediate') {
            return true;
        }

        if ($lastSentAt === null || trim($lastSentAt) === '') {
            return true;
        }

        $now = $now ?? new DateTimeImmutable('now');

        try {
            $lastSent = new DateTimeImmutable($lastSentAt);
        } catch (Exception $e) {
            return true;
        }

        if ($frequency === 'daily') {
            return $lastSent->modify('+1 day') <= $now;
        }

        if ($frequency === 'weekly') {
            return $lastSent->modify('+7 days') <= $now;
        }

        return true;
    }
}

if (!function_exists('conventa_invoice_notification_actor_key')) {
    function conventa_invoice_notification_actor_key(?string $value): string
    {
        $value = strtolower(trim(strip_tags((string) $value)));
        $value = preg_replace('/\s+/', ' ', $value) ?? $value;

        return $value;
    }
}

if (!function_exists('conventa_invoice_notification_user_tokens')) {
    function conventa_invoice_notification_user_tokens(array $user): array
    {
        $tokens = [];

        $name = conventa_invoice_notification_actor_key((string) ($user['name'] ?? ''));
        if ($name !== '') {
            $tokens[$name] = true;
        }

        $username = strtolower(trim((string) ($user['username'] ?? '')));
        if ($username !== '') {
            $tokens[$username] = true;
            $localPart = strstr($username, '@', true);
            if ($localPart !== false) {
                $tokens[conventa_invoice_notification_actor_key($localPart)] = true;
            }
        }

        return array_keys($tokens);
    }
}

if (!function_exists('conventa_invoice_notification_user_has_approved')) {
    function conventa_invoice_notification_user_has_approved(?string $approval, array $user): bool
    {
        $tokens = conventa_invoice_notification_user_tokens($user);
        if ($tokens === []) {
            return false;
        }

        preg_match_all('/\bAccepted\s+by\s*(.*?)(?:\(|<br\b|$)/i', (string) $approval, $matches);
        foreach ($matches[1] ?? [] as $actor) {
            $actorKey = conventa_invoice_notification_actor_key((string) $actor);
            if ($actorKey !== '' && in_array($actorKey, $tokens, true)) {
                return true;
            }
        }

        return false;
    }
}

if (!function_exists('conventa_invoice_notification_requires_user_action')) {
    function conventa_invoice_notification_requires_user_action(array $invoiceRow, array $user): bool
    {
        $approval = (string) ($invoiceRow['approval'] ?? '');
        $cts = trim((string) ($invoiceRow['cts'] ?? ''));

        if (stripos($approval, 'Processed by ') !== false || stripos($approval, 'Rejected by ') !== false) {
            return false;
        }

        if (conventa_invoice_notification_user_has_approved($approval, $user)) {
            return false;
        }

        if (conventa_invoice_requires_two_approvers($cts)) {
            return conventa_invoice_approval_count($approval) < 2;
        }

        return conventa_invoice_status_is_blank($approval);
    }
}

if (!function_exists('conventa_invoice_notification_preview')) {
    function conventa_invoice_notification_preview(PDO $pdo, array $filters = []): array
    {
        if (!conventa_invoice_notifications_available($pdo)) {
            throw new RuntimeException('Invoice notification schema is not available. Apply the notification migration first.');
        }

        $filterCts = trim((string) ($filters['cts'] ?? ''));
        $filterUser = strtolower(trim((string) ($filters['user'] ?? '')));
        $dueOnly = array_key_exists('due_only', $filters) ? (bool) $filters['due_only'] : true;

        $invoiceSql = "SELECT ID, cts, property, supplier, price, invoice, filename, approval
            FROM invoices
            WHERE COALESCE(approval, '') NOT LIKE '%Processed by%'
              AND COALESCE(approval, '') NOT LIKE '%Rejected by%'"; 
        $invoiceParams = [];
        if ($filterCts !== '') {
            $invoiceSql .= ' AND cts = :cts';
            $invoiceParams[':cts'] = $filterCts;
        }
        $invoiceSql .= ' ORDER BY cts ASC, ID ASC';

        $invoiceStmt = $pdo->prepare($invoiceSql);
        $invoiceStmt->execute($invoiceParams);

        $invoicesByCts = [];
        foreach ($invoiceStmt->fetchAll(PDO::FETCH_ASSOC) as $invoiceRow) {
            $cts = trim((string) ($invoiceRow['cts'] ?? ''));
            if ($cts === '') {
                continue;
            }

            if (!isset($invoicesByCts[$cts])) {
                $invoicesByCts[$cts] = [];
            }
            $invoicesByCts[$cts][] = $invoiceRow;
        }

        if ($invoicesByCts === []) {
            return [];
        }

        $userSql = "SELECT id, name, username, cts, notification_frequency, notification_last_sent_at
            FROM users
            WHERE TRIM(COALESCE(cts, '')) <> ''
              AND TRIM(COALESCE(username, '')) <> ''";
        $userParams = [];

        if ($filterCts !== '') {
            $userSql .= ' AND cts = :cts';
            $userParams[':cts'] = $filterCts;
        }

        if ($filterUser !== '') {
            $userSql .= ' AND LOWER(username) = :username';
            $userParams[':username'] = $filterUser;
        }

        $userSql .= ' ORDER BY cts ASC, username ASC';

        $userStmt = $pdo->prepare($userSql);
        $userStmt->execute($userParams);

        $preview = [];
        foreach ($userStmt->fetchAll(PDO::FETCH_ASSOC) as $user) {
            $cts = trim((string) ($user['cts'] ?? ''));
            if ($cts === '' || !isset($invoicesByCts[$cts])) {
                continue;
            }

            $userInvoices = array_values(array_filter(
                $invoicesByCts[$cts],
                static function (array $invoiceRow) use ($user): bool {
                    return conventa_invoice_notification_requires_user_action($invoiceRow, $user);
                }
            ));

            if ($userInvoices === []) {
                continue;
            }

            $frequency = conventa_normalize_invoice_notification_frequency((string) ($user['notification_frequency'] ?? 'immediate'));
            $lastSentAt = isset($user['notification_last_sent_at']) ? (string) $user['notification_last_sent_at'] : null;
            $isDue = conventa_invoice_notification_is_due($frequency, $lastSentAt);

            if ($dueOnly && !$isDue) {
                continue;
            }

            $invoiceIds = array_values(array_filter(array_map(static function (array $invoice): int {
                return (int) ($invoice['ID'] ?? 0);
            }, $userInvoices)));

            $preview[] = [
                'user_id' => (int) ($user['id'] ?? 0),
                'name' => (string) ($user['name'] ?? ''),
                'email' => strtolower(trim((string) ($user['username'] ?? ''))),
                'cts' => $cts,
                'frequency' => $frequency,
                'last_sent_at' => $lastSentAt,
                'is_due' => $isDue,
                'pending_invoice_count' => count($userInvoices),
                'invoice_ids' => $invoiceIds,
                'invoices' => $userInvoices,
            ];
        }

        return $preview;
    }
}

if (!function_exists('conventa_invoice_notification_storage_path')) {
    function conventa_invoice_notification_storage_path(string $relativePath = ''): string
    {
        $basePath = dirname(__DIR__) . '/storage/invoice-notifications';
        if (!is_dir($basePath)) {
            @mkdir($basePath, 0700, true);
        }

        if ($relativePath === '') {
            return $basePath;
        }

        return $basePath . '/' . ltrim($relativePath, '/');
    }
}

if (!function_exists('conventa_record_invoice_notification_outbox')) {
    function conventa_record_invoice_notification_outbox(array $entry): void
    {
        $path = conventa_invoice_notification_storage_path(
            'outbox-' . date('Ymd-His') . '-' . substr(hash('sha256', json_encode($entry) . microtime(true)), 0, 12) . '.json'
        );
        file_put_contents($path, json_encode($entry, JSON_PRETTY_PRINT), LOCK_EX);
    }
}

if (!function_exists('conventa_build_invoice_notification_message')) {
    function conventa_build_invoice_notification_message(array $notification): array
    {
        $baseUrl = rtrim((string) conventa_env('CONVENTA_BASE_URL', ''), '/');
        if ($baseUrl === '') {
            $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
            $host = (string) ($_SERVER['HTTP_HOST'] ?? 'localhost');
            $baseUrl = $scheme . '://' . $host;
        }
        $subject = 'Invoices awaiting approval for CTS ' . (string) ($notification['cts'] ?? '');
        $name = htmlspecialchars(trim((string) ($notification['name'] ?? '')), ENT_QUOTES, 'UTF-8');
        $cts = htmlspecialchars((string) ($notification['cts'] ?? ''), ENT_QUOTES, 'UTF-8');
        $frequency = htmlspecialchars(ucfirst((string) ($notification['frequency'] ?? 'Immediate')), ENT_QUOTES, 'UTF-8');
        $pendingCount = (int) ($notification['pending_invoice_count'] ?? 0);
        $portalUrl = htmlspecialchars('https://www.dcsmanagement.au/dcsinv/', ENT_QUOTES, 'UTF-8');

        $rows = '';
        foreach ((array) ($notification['invoices'] ?? []) as $invoice) {
            $rows .= '<tr>'
                . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;">' . htmlspecialchars((string) ($invoice['ID'] ?? ''), ENT_QUOTES, 'UTF-8') . '</td>'
                . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;">' . htmlspecialchars(trim((string) ($invoice['property'] ?? '')), ENT_QUOTES, 'UTF-8') . '</td>'
                . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;">' . htmlspecialchars(trim((string) ($invoice['supplier'] ?? '')), ENT_QUOTES, 'UTF-8') . '</td>'
                . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;">' . htmlspecialchars(trim((string) ($invoice['invoice'] ?? '')), ENT_QUOTES, 'UTF-8') . '</td>'
                . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;text-align:right;white-space:nowrap;">' . htmlspecialchars(trim((string) ($invoice['price'] ?? '')), ENT_QUOTES, 'UTF-8') . '</td>'
                . '</tr>';
        }

        $greeting = $name !== '' ? '<p style="margin:0 0 16px;">Hello ' . $name . ',</p>' : '';

        $body = '<!doctype html><html><body style="margin:0;padding:0;background:#f4f6f8;font-family:Arial,sans-serif;color:#1f2937;">'
            . '<div style="max-width:760px;margin:0 auto;padding:24px 16px;">'
            . '<div style="background:#0f172a;color:#ffffff;border-radius:12px 12px 0 0;padding:20px 24px;">'
            . '<div style="font-size:12px;letter-spacing:.08em;text-transform:uppercase;opacity:.85;">DCS Management</div>'
            . '<h1 style="margin:8px 0 0;font-size:24px;line-height:1.2;">Invoices Awaiting Approval</h1>'
            . '</div>'
            . '<div style="background:#ffffff;border:1px solid #dbe2ea;border-top:none;border-radius:0 0 12px 12px;padding:24px;">'
            . $greeting
            . '<p style="margin:0 0 16px;">You have invoices awaiting approval in the Invoice Approval Portal.</p>'
            . '<table style="width:100%;border-collapse:collapse;margin:0 0 20px;">'
            . '<tr>'
            . '<td style="padding:12px;background:#f8fafc;border:1px solid #e5e7eb;"><strong>CTS</strong><br>' . $cts . '</td>'
            . '<td style="padding:12px;background:#f8fafc;border:1px solid #e5e7eb;"><strong>Pending invoices</strong><br>' . $pendingCount . '</td>'
            . '<td style="padding:12px;background:#f8fafc;border:1px solid #e5e7eb;"><strong>Notification frequency</strong><br>' . $frequency . '</td>'
            . '</tr>'
            . '</table>'
            . '<table style="width:100%;border-collapse:collapse;margin:0 0 24px;font-size:14px;">'
            . '<thead><tr style="background:#eff6ff;">'
            . '<th style="text-align:left;padding:10px 12px;border-bottom:2px solid #cbd5e1;">ID</th>'
            . '<th style="text-align:left;padding:10px 12px;border-bottom:2px solid #cbd5e1;">Property</th>'
            . '<th style="text-align:left;padding:10px 12px;border-bottom:2px solid #cbd5e1;">Supplier</th>'
            . '<th style="text-align:left;padding:10px 12px;border-bottom:2px solid #cbd5e1;">Invoice</th>'
            . '<th style="text-align:right;padding:10px 12px;border-bottom:2px solid #cbd5e1;">Amount</th>'
            . '</tr></thead><tbody>' . $rows . '</tbody></table>'
            . '<div style="margin:0 0 20px;">'
            . '<a href="' . $portalUrl . '" style="display:inline-block;background:#0ea5e9;color:#ffffff;text-decoration:none;padding:12px 20px;border-radius:8px;font-weight:700;">Open Invoice Portal</a>'
            . '</div>'
            . '<p style="margin:0;color:#6b7280;font-size:13px;">This is an automated reminder based on your invoice notification preference.</p>'
            . '</div></div></body></html>';

        return [
            'subject' => $subject,
            'body' => $body,
        ];
    }
}

if (!function_exists('conventa_send_invoice_notification')) {
    function conventa_send_invoice_notification(array $notification): array
    {
        $email = strtolower(trim((string) ($notification['email'] ?? '')));
        $frequency = conventa_normalize_invoice_notification_frequency((string) ($notification['frequency'] ?? 'immediate'));
        $message = conventa_build_invoice_notification_message($notification);

        if ($email === '') {
            return ['success' => false, 'mode' => 'skipped'];
        }

        $sent = conventa_smtp_send_html($email, $message['subject'], $message['body']);
        if (!$sent) {
            conventa_record_invoice_notification_outbox([
                'to' => $email,
                'frequency' => $frequency,
                'invoice_ids' => array_values((array) ($notification['invoice_ids'] ?? [])),
                'subject' => $message['subject'],
                'body' => $message['body'],
                'created_at' => date(DATE_ATOM),
            ]);

            return ['success' => false, 'mode' => 'outbox'];
        }

        return ['success' => true, 'mode' => 'smtp'];
    }
}

if (!function_exists('conventa_log_invoice_notification')) {
    function conventa_log_invoice_notification(PDO $pdo, array $notification, string $triggerMode = 'manual'): void
    {
        $stmt = $pdo->prepare('INSERT INTO invoice_notification_log
            (user_id, cts, frequency, trigger_mode, pending_invoice_count, invoice_ids_snapshot, sent_at)
            VALUES (:user_id, :cts, :frequency, :trigger_mode, :pending_invoice_count, :invoice_ids_snapshot, :sent_at)');
        $stmt->execute([
            ':user_id' => (int) ($notification['user_id'] ?? 0),
            ':cts' => (string) ($notification['cts'] ?? ''),
            ':frequency' => conventa_normalize_invoice_notification_frequency((string) ($notification['frequency'] ?? 'immediate')),
            ':trigger_mode' => $triggerMode,
            ':pending_invoice_count' => (int) ($notification['pending_invoice_count'] ?? 0),
            ':invoice_ids_snapshot' => json_encode(array_values((array) ($notification['invoice_ids'] ?? []))),
            ':sent_at' => date('Y-m-d H:i:s'),
        ]);
    }
}

if (!function_exists('conventa_update_invoice_notification_last_sent_at')) {
    function conventa_update_invoice_notification_last_sent_at(PDO $pdo, int $userId): void
    {
        $stmt = $pdo->prepare('UPDATE users SET notification_last_sent_at = :sent_at WHERE id = :id');
        $stmt->execute([
            ':sent_at' => date('Y-m-d H:i:s'),
            ':id' => $userId,
        ]);
    }
}

if (!function_exists('conventa_process_invoice_notifications')) {
    function conventa_process_invoice_notifications(PDO $pdo, array $filters = []): array
    {
        $notifications = conventa_invoice_notification_preview($pdo, $filters);
        $results = [];

        foreach ($notifications as $notification) {
            $sendResult = conventa_send_invoice_notification($notification);
            if (($sendResult['mode'] ?? '') === 'smtp' || ($sendResult['mode'] ?? '') === 'outbox') {
                conventa_log_invoice_notification($pdo, $notification, (string) ($filters['trigger_mode'] ?? 'manual'));
                conventa_update_invoice_notification_last_sent_at($pdo, (int) ($notification['user_id'] ?? 0));
            }

            $results[] = [
                'notification' => $notification,
                'result' => $sendResult,
            ];
        }

        return $results;
    }
}
