import { agentIntegrationChatBindings, agents, approvals, chatConversationUserStates, chatConversations, chatMessages, heartbeatRuns, } from "@rudderhq/db";
import { and, eq, inArray, sql } from "drizzle-orm";
import { visibleIncomingMessageSql } from "./chats.helpers.js";
import { messengerService } from "./messenger.js";
const ACTIONABLE_APPROVAL_STATUSES = ["pending"];
function buildBadges(base, extra) {
    const joinRequests = extra?.joinRequests ?? 0;
    const unreadTouchedIssues = extra?.unreadTouchedIssues ?? 0;
    const chatAttention = extra?.chatAttention ?? 0;
    const alerts = extra?.alerts ?? 0;
    return {
        inbox: base.approvals +
            base.failedRuns +
            joinRequests +
            unreadTouchedIssues +
            chatAttention +
            alerts,
        approvals: base.approvals,
        failedRuns: base.failedRuns,
        joinRequests,
        unreadTouchedIssues,
        chatAttention,
        alerts,
    };
}
export function sidebarBadgeService(db) {
    const messengerSvc = messengerService(db);
    async function countActionableApprovals(orgId) {
        return db
            .select({ count: sql `count(*)` })
            .from(approvals)
            .where(and(eq(approvals.orgId, orgId), inArray(approvals.status, ACTIONABLE_APPROVAL_STATUSES)))
            .then((rows) => Number(rows[0]?.count ?? 0));
    }
    async function countFailedLatestRuns(orgId) {
        const rows = await db.execute(sql `
      select count(*)::int as count
      from (
        select
          ${heartbeatRuns.status} as run_status,
          row_number() over (
            partition by ${heartbeatRuns.agentId}
            order by ${heartbeatRuns.createdAt} desc
          ) as run_rank
        from ${heartbeatRuns}
        inner join ${agents}
          on ${heartbeatRuns.agentId} = ${agents.id}
          and ${agents.orgId} = ${orgId}
        where ${heartbeatRuns.orgId} = ${orgId}
          and ${agents.status} <> 'terminated'
      ) latest_agent_runs
      where latest_agent_runs.run_rank = 1
        and latest_agent_runs.run_status in ('failed', 'timed_out')
    `);
        return Number(rows[0]?.count ?? 0);
    }
    async function ensureActiveChatUserStates(orgId, userId) {
        await db.execute(sql `
      insert into chat_conversation_user_states (
        org_id,
        conversation_id,
        user_id,
        last_read_at,
        updated_at
      )
      select
        ${chatConversations.orgId},
        ${chatConversations.id},
        ${userId},
        coalesce(${chatConversations.lastMessageAt}, ${chatConversations.updatedAt}, ${chatConversations.createdAt}),
        now()
      from ${chatConversations}
      where ${chatConversations.orgId} = ${orgId}
        and ${chatConversations.status} = 'active'
      on conflict (org_id, conversation_id, user_id) do nothing
    `);
    }
    return {
        countUnreadTouchedIssues: async (orgId, userId) => {
            return messengerSvc.countUnreadIssueThreadEntries(orgId, userId);
        },
        getMessengerUnreadCounts: async (orgId, userId, options = {}) => {
            const summaries = await messengerSvc.listThreadSummaries(orgId, userId);
            const unreadCountFor = (threadKey) => summaries.find((summary) => summary.threadKey === threadKey)?.unreadCount ?? 0;
            const chatAttention = summaries
                .filter((summary) => summary.kind === "chat")
                .reduce((total, summary) => total + Math.max(0, summary.unreadCount), 0);
            return buildBadges({
                approvals: unreadCountFor("approvals"),
                failedRuns: unreadCountFor("failed-runs"),
            }, {
                joinRequests: options.includeJoinRequests ? unreadCountFor("join-requests") : 0,
                unreadTouchedIssues: unreadCountFor("issues"),
                chatAttention,
                alerts: unreadCountFor("budget-alerts"),
            });
        },
        countActiveChatAttention: async (orgId, userId) => {
            await ensureActiveChatUserStates(orgId, userId);
            return db
                .select({ count: sql `count(*)` })
                .from(chatConversations)
                .where(and(eq(chatConversations.orgId, orgId), eq(chatConversations.status, "active"), sql `(
              exists (
                select 1
                from ${chatMessages}
                inner join ${chatConversationUserStates}
                  on ${chatConversationUserStates.orgId} = ${orgId}
                  and ${chatConversationUserStates.userId} = ${userId}
                  and ${chatConversationUserStates.conversationId} = ${chatMessages.conversationId}
                where ${chatMessages.orgId} = ${orgId}
                  and ${chatMessages.conversationId} = ${chatConversations.id}
                  and ${chatMessages.supersededAt} is null
                  and ${visibleIncomingMessageSql()}
                  and ${chatMessages.createdAt} > ${chatConversationUserStates.lastReadAt}
                  and not exists (
                    select 1
                    from ${agentIntegrationChatBindings}
                    where ${agentIntegrationChatBindings.orgId} = ${orgId}
                      and ${agentIntegrationChatBindings.conversationId} = ${chatMessages.conversationId}
                  )
              )
              or exists (
                select 1
                from ${chatMessages}
                inner join ${approvals} on ${chatMessages.approvalId} = ${approvals.id}
                where ${chatMessages.orgId} = ${orgId}
                  and ${chatMessages.conversationId} = ${chatConversations.id}
                  and ${chatMessages.supersededAt} is null
                  and ${approvals.orgId} = ${orgId}
                  and ${approvals.status} = 'pending'
                  and not exists (
                    select 1
                    from ${agentIntegrationChatBindings}
                    where ${agentIntegrationChatBindings.orgId} = ${orgId}
                      and ${agentIntegrationChatBindings.conversationId} = ${chatMessages.conversationId}
                  )
              )
            )`))
                .then((rows) => Number(rows[0]?.count ?? 0));
        },
        getBaseCounts: async (orgId) => {
            const [approvals, failedRuns] = await Promise.all([
                countActionableApprovals(orgId),
                countFailedLatestRuns(orgId),
            ]);
            return { approvals, failedRuns };
        },
        get: async (orgId, extra) => {
            const [approvals, failedRuns] = await Promise.all([
                countActionableApprovals(orgId),
                countFailedLatestRuns(orgId),
            ]);
            return buildBadges({ approvals, failedRuns }, extra);
        },
        fromCounts: buildBadges,
    };
}
//# sourceMappingURL=sidebar-badges.js.map