import { eq, and, isNull, desc, gte, lte, ilike, or } from "drizzle-orm"; import { db } from "@/db"; import { leads, activities, reminders, quotes, clientTranscripts } from "@/db/schema"; // Get all leads export async function getAllLeads(limit: number = 100, offset: number = 0) { return await db .select() .from(leads) .orderBy(desc(leads.updated_at)) .limit(limit) .offset(offset); } // Get lead by ID export async function getLeadById(id: string) { const [lead] = await db .select() .from(leads) .where(eq(leads.id, id)); return lead; } // Get leads by stage export async function getLeadsByStage(stage: string) { return await db .select() .from(leads) .where(eq(leads.status, stage)) .orderBy(desc(leads.last_contact_date)); } // Get leads needing follow-up export async function getLeadsNeedingFollowUp(daysAgo: number = 7) { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - daysAgo); return await db .select() .from(leads) .where( or( isNull(leads.last_contact_date), lte(leads.last_contact_date, cutoffDate) ) ) .orderBy(leads.created_at); } // Get activity log export async function getActivityLog(leadId: string) { return await db .select() .from(activities) .where(eq(activities.lead_id, leadId)) .orderBy(desc(activities.activity_date)); } // Get upcoming reminders export async function getUpcomingReminders(leadId: string) { return await db .select() .from(reminders) .where(and(eq(reminders.lead_id, leadId), isNull(reminders.completed_at))) .orderBy(reminders.due_date); } // Get overdue reminders export async function getOverdueReminders() { const now = new Date(); return await db .select() .from(reminders) .where(and(lte(reminders.due_date, now), isNull(reminders.completed_at))) .orderBy(reminders.due_date); } // Create activity and auto-update last_contact_date export async function createActivity(data: { lead_id: string; type: string; activity_date: Date | string; duration_minutes?: number; notes: string; }) { const activityDate = typeof data.activity_date === "string" ? new Date(data.activity_date) : data.activity_date; const [activity] = await db .insert(activities) .values({ lead_id: data.lead_id, type: data.type, activity_date: activityDate, duration_minutes: data.duration_minutes, notes: data.notes, }) .returning(); // Auto-update lead.last_contact_date await db .update(leads) .set({ last_contact_date: activityDate, updated_at: new Date() }) .where(eq(leads.id, data.lead_id)); return activity; } // Update lead stage export async function updateLeadStage(leadId: string, stage: string) { const [updated] = await db .update(leads) .set({ status: stage, updated_at: new Date() }) .where(eq(leads.id, leadId)) .returning(); return updated; } // Update lead export async function updateLead( leadId: string, data: Partial<{ name: string; email: string; phone: string; company: string; notes: string; next_action: string; next_action_date: Date | string; }> ) { const updateData: Record = { updated_at: new Date() }; if (data.name !== undefined) updateData.name = data.name; if (data.email !== undefined) updateData.email = data.email; if (data.phone !== undefined) updateData.phone = data.phone; if (data.company !== undefined) updateData.company = data.company; if (data.notes !== undefined) updateData.notes = data.notes; if (data.next_action !== undefined) updateData.next_action = data.next_action; if (data.next_action_date !== undefined) { updateData.next_action_date = typeof data.next_action_date === "string" ? new Date(data.next_action_date) : data.next_action_date; } const [updated] = await db .update(leads) .set(updateData) .where(eq(leads.id, leadId)) .returning(); return updated; } // Search leads export async function searchLeads(query: string) { return await db .select() .from(leads) .where( or( ilike(leads.name, `%${query}%`), ilike(leads.email, `%${query}%`), ilike(leads.company, `%${query}%`) ) ) .orderBy(desc(leads.updated_at)); } // Create reminder export async function createReminder(data: { lead_id: string; title: string; description?: string; due_date: Date | string; }) { const dueDate = typeof data.due_date === "string" ? new Date(data.due_date) : data.due_date; const [reminder] = await db .insert(reminders) .values({ lead_id: data.lead_id, title: data.title, description: data.description, due_date: dueDate, }) .returning(); return reminder; } // Complete reminder export async function completeReminder(reminderId: string) { const [updated] = await db .update(reminders) .set({ completed_at: new Date() }) .where(eq(reminders.id, reminderId)) .returning(); return updated; } // Get quotes by lead export async function getQuotesByLeadId(leadId: string) { return await db .select() .from(quotes) .where(eq(quotes.lead_id, leadId)) .orderBy(desc(quotes.created_at)); } // Get transcript log for a lead — call_date DESC (D-05) // Returns all fields including full content (Phase 21 reads them in bulk). export async function getTranscripts(leadId: string) { return await db .select() .from(clientTranscripts) .where(eq(clientTranscripts.lead_id, leadId)) .orderBy(desc(clientTranscripts.call_date)); } // Get transcripts linked to a client (post lead→client conversion). // Returns all fields — used by admin DocumentsTab and public TranscriptsSection. export async function getTranscriptsByClientId(clientId: string) { return await db .select() .from(clientTranscripts) .where(eq(clientTranscripts.client_id, clientId)) .orderBy(desc(clientTranscripts.call_date)); }