import type { NextApiRequest, NextApiResponse } from "next" import { db, schema } from '../../../lib/db/connection' import { eq, and, or, like, gte, lte, desc, count, sql } from 'drizzle-orm' export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "GET") return res.status(405).json({ error: "Method not allowed" }) const { q, category, risk_level_min, risk_level_max, status = 'verified', page = '1', limit = '20' } = req.query try { let whereConditions = [eq(schema.sources.status, status as string)] if (q) { whereConditions.push( or( like(schema.sources.domain, `%${q}%`), like(schema.sources.title, `%${q}%`), like(schema.sources.description, `%${q}%`) ) ) } if (risk_level_min) { whereConditions.push(gte(schema.sources.riskLevel, parseInt(risk_level_min as string))) } if (risk_level_max) { whereConditions.push(lte(schema.sources.riskLevel, parseInt(risk_level_max as string))) } const offset = (parseInt(page as string) - 1) * parseInt(limit as string) const limitInt = parseInt(limit as string) // Build the base query let query = db .select({ id: schema.sources.id, domain: schema.sources.domain, title: schema.sources.title, riskLevel: schema.sources.riskLevel, description: schema.sources.description, createdAt: schema.sources.createdAt, categories: sql`string_agg(${schema.categories.name}, ',')` }) .from(schema.sources) .leftJoin(schema.sourceCategories, eq(schema.sources.id, schema.sourceCategories.sourceId)) .leftJoin(schema.categories, eq(schema.sourceCategories.categoryId, schema.categories.id)) .where(and(...whereConditions)) .groupBy(schema.sources.id, schema.sources.domain, schema.sources.title, schema.sources.riskLevel, schema.sources.description, schema.sources.createdAt) .orderBy(desc(schema.sources.riskLevel), desc(schema.sources.createdAt)) .limit(limitInt) .offset(offset) // Apply category filter if provided if (category) { query = db .select({ id: schema.sources.id, domain: schema.sources.domain, title: schema.sources.title, riskLevel: schema.sources.riskLevel, description: schema.sources.description, createdAt: schema.sources.createdAt, categories: sql`string_agg(${schema.categories.name}, ',')` }) .from(schema.sources) .innerJoin(schema.sourceCategories, eq(schema.sources.id, schema.sourceCategories.sourceId)) .innerJoin(schema.categories, eq(schema.sourceCategories.categoryId, schema.categories.id)) .where(and(...whereConditions, eq(schema.categories.name, category as string))) .groupBy(schema.sources.id, schema.sources.domain, schema.sources.title, schema.sources.riskLevel, schema.sources.description, schema.sources.createdAt) .orderBy(desc(schema.sources.riskLevel), desc(schema.sources.createdAt)) .limit(limitInt) .offset(offset) } const results = await query // Get total count for pagination let countQuery = db .select({ count: count() }) .from(schema.sources) .where(and(...whereConditions)) if (category) { countQuery = db .select({ count: count() }) .from(schema.sources) .innerJoin(schema.sourceCategories, eq(schema.sources.id, schema.sourceCategories.sourceId)) .innerJoin(schema.categories, eq(schema.sourceCategories.categoryId, schema.categories.id)) .where(and(...whereConditions, eq(schema.categories.name, category as string))) } const [totalResult] = await countQuery const total = totalResult.count const totalPages = Math.ceil(total / limitInt) res.json({ results: results.map(row => ({ id: row.id, domain: row.domain, title: row.title, risk_level: row.riskLevel, categories: row.categories ? row.categories.split(',').filter(Boolean) : [], description: row.description, created_at: row.createdAt })), pagination: { page: parseInt(page as string), limit: limitInt, total, totalPages } }) } catch (error) { console.error('Search error:', error) res.status(500).json({ error: "Search failed" }) } }