<?php
/**
 * Notifications — cross-role handoff inbox.
 *
 * Every workflow transition that hands work to someone else can drop a row here:
 *   Notifications::notify($userId, 'TENDER_WON', 'Contract terms needed for T-2026-0007', '...', 'Tenders/view/17')
 *
 * The top-nav bell reads unreadCountForUser(); the inbox page reads recentForUser().
 *
 * Fan-out helpers (notifyGroup) resolve a user_group_name → all active users in that
 * group. Useful for "any Finance Manager can pick this up" style handoffs.
 */
class Notifications extends Model
{
    /** Insert a notification. Silently no-ops if $userId <= 0. */
    public function notify(int $userId, string $kind, string $subject, string $body = '', string $targetUrl = '',
                           string $entityType = '', int $entityId = 0, int $createdBy = 0, string $createdByName = ''): int
    {
        if ($userId <= 0 || trim($subject) === '') return 0;
        $db = new DB();
        $fb = $db->insertUpdate(
            "INSERT INTO notifications
                (recipient_user_id, kind, subject, body, target_url,
                 entity_type, entity_id, created_by, created_by_name, created_on)
             VALUES (:u, :k, :sub, :bod, :url, :et, :eid, :cb, :cbn, NOW())",
            [
                ':u' => $userId, ':k' => $kind, ':sub' => $subject, ':bod' => $body,
                ':url' => $targetUrl, ':et' => $entityType, ':eid' => $entityId,
                ':cb' => $createdBy, ':cbn' => $createdByName,
            ]
        );
        return (int)($fb['last_id'] ?? 0);
    }

    /** Fan out to every active user in a given group. Returns the count that got a row. */
    public function notifyGroup(string $groupName, string $kind, string $subject, string $body = '', string $targetUrl = '',
                                string $entityType = '', int $entityId = 0, int $createdBy = 0, string $createdByName = ''): int
    {
        $db = new DB();
        $users = $db->mySelect(
            "SELECT c0d FROM users WHERE user_group_name = :g AND status = 'ACTIVE' AND deleted = 0",
            [':g' => $groupName]
        ) ?: [];
        $n = 0;
        foreach ($users as $u) {
            if ($this->notify((int)$u['c0d'], $kind, $subject, $body, $targetUrl, $entityType, $entityId, $createdBy, $createdByName) > 0) $n++;
        }
        return $n;
    }

    public function unreadCountForUser(int $userId): int
    {
        if ($userId <= 0) return 0;
        $db = new DB();
        $r = $db->mySelect(
            "SELECT COUNT(*) n FROM notifications WHERE recipient_user_id = :u AND read_on IS NULL AND deleted = 0",
            [':u' => $userId]
        );
        return (int)($r[0]['n'] ?? 0);
    }

    public function recentForUser(int $userId, int $limit = 50, bool $unreadOnly = false): array
    {
        if ($userId <= 0) return [];
        $limit = max(1, min(500, $limit));
        $extra = $unreadOnly ? ' AND read_on IS NULL' : '';
        $db = new DB();
        return $db->mySelect(
            "SELECT * FROM notifications
              WHERE recipient_user_id = :u AND deleted = 0 $extra
              ORDER BY created_on DESC, c0d DESC
              LIMIT $limit",
            [':u' => $userId]
        ) ?: [];
    }

    public function markRead(int $notificationId, int $userId): bool
    {
        if ($notificationId <= 0 || $userId <= 0) return false;
        $db = new DB();
        $db->insertUpdate(
            "UPDATE notifications SET read_on = NOW()
              WHERE c0d = :id AND recipient_user_id = :u AND read_on IS NULL AND deleted = 0",
            [':id' => $notificationId, ':u' => $userId]
        );
        return true;
    }

    public function markAllRead(int $userId): int
    {
        if ($userId <= 0) return 0;
        $db = new DB();
        $db->insertUpdate(
            "UPDATE notifications SET read_on = NOW()
              WHERE recipient_user_id = :u AND read_on IS NULL AND deleted = 0",
            [':u' => $userId]
        );
        return 1;
    }
}
