'use strict' const { query, queryOne } = require('../database/postgres') class GroupChat { /** * Listar grupos em que o colaborador participa (via team_members) com unread_count */ static async listForAccount(tenantId, accountId) { return query( `SELECT gc.id, gc.sector_id, gc.name, s.icon, s.color, (SELECT gm.content FROM group_messages gm WHERE gm.group_chat_id = gc.id ORDER BY gm.created_at DESC LIMIT 1) AS last_message, (SELECT gm.created_at FROM group_messages gm WHERE gm.group_chat_id = gc.id ORDER BY gm.created_at DESC LIMIT 1) AS last_message_at, (SELECT COUNT(*)::int FROM group_messages gm2 LEFT JOIN group_last_read glr ON glr.group_chat_id = gm2.group_chat_id AND glr.account_id = $2 WHERE gm2.group_chat_id = gc.id AND gm2.from_account != $2 AND (glr.last_read_at IS NULL OR gm2.created_at > glr.last_read_at) ) AS unread_count FROM group_chats gc JOIN sectors s ON s.id = gc.sector_id JOIN team_members tm ON tm.sector_id = gc.sector_id AND tm.account_id = $2 WHERE gc.tenant_id = $1 ORDER BY s.sort_order, gc.name`, [tenantId, accountId] ) } /** * Listar todos os grupos do tenant (para owners/managers) com unread_count */ static async listAll(tenantId, accountId) { return query( `SELECT gc.id, gc.sector_id, gc.name, s.icon, s.color, (SELECT gm.content FROM group_messages gm WHERE gm.group_chat_id = gc.id ORDER BY gm.created_at DESC LIMIT 1) AS last_message, (SELECT gm.created_at FROM group_messages gm WHERE gm.group_chat_id = gc.id ORDER BY gm.created_at DESC LIMIT 1) AS last_message_at, (SELECT COUNT(*)::int FROM group_messages gm2 LEFT JOIN group_last_read glr ON glr.group_chat_id = gm2.group_chat_id AND glr.account_id = $2 WHERE gm2.group_chat_id = gc.id AND gm2.from_account != $2 AND (glr.last_read_at IS NULL OR gm2.created_at > glr.last_read_at) ) AS unread_count FROM group_chats gc JOIN sectors s ON s.id = gc.sector_id WHERE gc.tenant_id = $1 ORDER BY s.sort_order, gc.name`, [tenantId, accountId] ) } /** * Marcar grupo como lido (upsert last_read_at) */ static async markRead(accountId, groupChatId) { await queryOne( `INSERT INTO group_last_read (account_id, group_chat_id, last_read_at) VALUES ($1, $2, NOW()) ON CONFLICT (account_id, group_chat_id) DO UPDATE SET last_read_at = NOW()`, [accountId, groupChatId] ) } /** * Buscar grupo por id, verificando pertença ao tenant */ static async findById(tenantId, groupChatId) { return queryOne( `SELECT gc.*, s.name AS sector_name, s.icon, s.color, (SELECT COUNT(*)::int FROM team_members tm WHERE tm.sector_id = s.id) AS member_count FROM group_chats gc JOIN sectors s ON s.id = gc.sector_id WHERE gc.id = $1 AND gc.tenant_id = $2`, [groupChatId, tenantId] ) } /** * Buscar mensagens de um grupo (paginação por cursor) */ static async getMessages(tenantId, groupChatId, limit = 50, before = null) { const params = [tenantId, groupChatId, limit] const beforeClause = before ? `AND gm.created_at < $4` : '' if (before) params.push(before) const msgs = await query( `SELECT gm.id, gm.from_account, gm.content, gm.created_at, a.name AS sender_name, a.avatar_url AS sender_avatar FROM group_messages gm LEFT JOIN accounts a ON a.id = gm.from_account WHERE gm.tenant_id = $1 AND gm.group_chat_id = $2 ${beforeClause} ORDER BY gm.created_at DESC LIMIT $3`, params ) return msgs.reverse() } /** * Enviar mensagem em um grupo */ static async sendMessage(tenantId, groupChatId, fromAccount, content) { return queryOne( `INSERT INTO group_messages (tenant_id, group_chat_id, from_account, content) VALUES ($1, $2, $3, $4) RETURNING id, group_chat_id, from_account, content, created_at`, [tenantId, groupChatId, fromAccount, content] ) } /** * Listar membros de um grupo (via team_members do setor) */ static async getMembers(tenantId, groupChatId) { return query( `SELECT a.id, a.name, a.avatar_url, a.availability FROM group_chats gc JOIN team_members tm ON tm.sector_id = gc.sector_id JOIN accounts a ON a.id = tm.account_id WHERE gc.id = $1 AND gc.tenant_id = $2 AND a.active = TRUE ORDER BY a.name`, [groupChatId, tenantId] ) } /** * IDs dos membros de um grupo (para SSE direcionado) */ static async getMemberIds(groupChatId) { const rows = await query( `SELECT tm.account_id FROM group_chats gc JOIN team_members tm ON tm.sector_id = gc.sector_id WHERE gc.id = $1`, [groupChatId] ) return rows.map(r => r.account_id) } } module.exports = GroupChat