import { getDb } from '../db/client.js' import * as valkey from '../plugins/valkey.js' import { VK_MITRAS_ONLINE } from './mitra-status.service.js' import { SessionStatus, TopicSensitivity } from '../constants.js' const sql = getDb() // Valkey-fast SCARD with Postgres fallback. The CC dashboard polls every few // seconds; SCARD is sub-ms so this keeps the dashboard responsive at any scale. const getOnlineMitrasCount = async () => { try { return await valkey.scard(VK_MITRAS_ONLINE) } catch (err) { console.warn('[dashboard] valkey unavailable, falling back to DB:', err.message) const [{ c }] = await sql`SELECT COUNT(*)::int AS c FROM mitra_online_status WHERE is_online = true` return c } } export const getDashboardStats = async () => { const [ [{ active_chats }], online_mitras, [{ pending_requests }], [{ sensitive_total }], [{ sensitive_last_30d_total }], [{ sensitive_last_30d_sensitive }], ] = await Promise.all([ sql`SELECT COUNT(*) AS active_chats FROM chat_sessions WHERE status IN (${SessionStatus.ACTIVE}, ${SessionStatus.PENDING_PAYMENT})`, getOnlineMitrasCount(), sql`SELECT COUNT(*) AS pending_requests FROM chat_sessions WHERE status IN (${SessionStatus.SEARCHING}, ${SessionStatus.PENDING_ACCEPTANCE})`, sql`SELECT COUNT(*) AS sensitive_total FROM chat_sessions WHERE topic_sensitivity = ${TopicSensitivity.SENSITIVE}`, sql`SELECT COUNT(*) AS sensitive_last_30d_total FROM chat_sessions WHERE created_at >= NOW() - INTERVAL '30 days'`, sql`SELECT COUNT(*) AS sensitive_last_30d_sensitive FROM chat_sessions WHERE created_at >= NOW() - INTERVAL '30 days' AND topic_sensitivity = ${TopicSensitivity.SENSITIVE}`, ]) const customersPerMitra = await sql` SELECT m.id, m.display_name, (SELECT COUNT(*) FROM chat_sessions cs WHERE cs.mitra_id = m.id AND cs.status IN (${SessionStatus.ACTIVE}, ${SessionStatus.PENDING_PAYMENT})) AS active_session_count FROM mitras m INNER JOIN mitra_online_status s ON s.mitra_id = m.id WHERE s.is_online = true ORDER BY active_session_count DESC ` const last30dTotal = Number(sensitive_last_30d_total) const last30dSensitive = Number(sensitive_last_30d_sensitive) return { active_chats: Number(active_chats), online_mitras: Number(online_mitras), pending_requests: Number(pending_requests), customers_per_mitra: customersPerMitra, sensitive: { total: Number(sensitive_total), last_30d_total: last30dTotal, last_30d_sensitive: last30dSensitive, last_30d_percent: last30dTotal > 0 ? Math.round((last30dSensitive / last30dTotal) * 1000) / 10 : 0, }, } }