import { and, desc, eq, inArray, isNull, not, sql } from 'drizzle-orm';
import { db } from '../config/database.js';
import { contacts, emailAccounts, emails, userEmailAccounts } from '../db/schema.js';

export const getCompanyEmailThreads = async (companyId, userId) => {
  const accountLinks = await db
    .select({
      id: emailAccounts.id,
      email: emailAccounts.email,
      isActive: emailAccounts.isActive,
    })
    .from(userEmailAccounts)
    .innerJoin(emailAccounts, eq(userEmailAccounts.emailAccountId, emailAccounts.id))
    .where(
      and(
        eq(userEmailAccounts.userId, userId),
        eq(emailAccounts.isActive, true)
      )
    );

  const accountIds = accountLinks.map((acc) => acc.id);

  if (accountIds.length === 0) {
    return { accounts: [], threads: [] };
  }

  const rows = await db
    .select({
      threadId: emails.threadId,
      emailAccountId: emails.emailAccountId,
      accountEmail: emailAccounts.email,
      subject: emails.subject,
      date: emails.date,
      isRead: emails.isRead,
      from: emails.from,
      to: emails.to,
      contactId: contacts.id,
      contactEmail: contacts.email,
      contactName: contacts.name,
    })
    .from(emails)
    .innerJoin(emailAccounts, eq(emails.emailAccountId, emailAccounts.id))
    .leftJoin(contacts, eq(emails.contactId, contacts.id))
    .where(
      and(
        inArray(emails.emailAccountId, accountIds),
        eq(emails.companyId, companyId)
      )
    )
    .orderBy(desc(emails.date));

  const threadsMap = new Map();

  for (const row of rows) {
    const threadKey = `${row.emailAccountId}:${row.threadId}`;
    const lastDate = row.date ? new Date(row.date) : null;
    const existing = threadsMap.get(threadKey);

    if (!existing) {
      threadsMap.set(threadKey, {
        threadId: row.threadId,
        emailAccountId: row.emailAccountId,
        accountEmail: row.accountEmail,
        contactId: row.contactId,
        contactEmail: row.contactEmail,
        contactName: row.contactName,
        subject: row.subject,
        lastFrom: row.from,
        lastTo: row.to,
        lastMessageAt: lastDate,
        unreadCount: row.isRead ? 0 : 1,
        totalCount: 1,
      });
      continue;
    }

    existing.totalCount += 1;
    if (!row.isRead) {
      existing.unreadCount += 1;
    }

    if (lastDate && (!existing.lastMessageAt || lastDate > existing.lastMessageAt)) {
      existing.lastMessageAt = lastDate;
      existing.subject = row.subject;
      existing.lastFrom = row.from;
      existing.lastTo = row.to;
    }
  }

  const threads = Array.from(threadsMap.values()).sort((a, b) => {
    const aTime = a.lastMessageAt ? a.lastMessageAt.getTime() : 0;
    const bTime = b.lastMessageAt ? b.lastMessageAt.getTime() : 0;
    return bTime - aTime;
  });

  return {
    accounts: accountLinks,
    threads,
  };
};

export const getCompanyUnreadCounts = async (userId) => {
  const accountLinks = await db
    .select({ id: emailAccounts.id })
    .from(userEmailAccounts)
    .innerJoin(emailAccounts, eq(userEmailAccounts.emailAccountId, emailAccounts.id))
    .where(
      and(
        eq(userEmailAccounts.userId, userId),
        eq(emailAccounts.isActive, true)
      )
    );

  const accountIds = accountLinks.map((acc) => acc.id);

  if (accountIds.length === 0) {
    return [];
  }

  const rows = await db
    .select({
      companyId: emails.companyId,
      unreadCount: sql`count(*)::int`,
    })
    .from(emails)
    .where(
      and(
        inArray(emails.emailAccountId, accountIds),
        eq(emails.isRead, false),
        not(isNull(emails.companyId))
      )
    )
    .groupBy(emails.companyId);

  return rows;
};
