import { NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { db } from '@/lib/db'
import { visible } from '@/lib/scope'

export const runtime = 'nodejs'

type Hit = { type: 'reminder' | 'thought' | 'item' | 'list' | 'capture' | 'event'; id: string; title: string; sub: string | null; href: string }

const PER = 6 // cap per group so the palette stays snappy
function clip(s: string, n = 80) { const t = s.replace(/\s+/g, ' ').trim(); return t.length > n ? t.slice(0, n - 1) + '…' : t }

// GET /api/search?q=… — one flat, type-ordered result list across everything
// searchable (reminders, thoughts, list items + lists, captures, events).
export async function GET(req: Request) {
  const session = await getSession()
  if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 })

  const q = new URL(req.url).searchParams.get('q')?.trim() || ''
  if (q.length < 2) return NextResponse.json({ results: [] })

  // Token-based: every word must appear (in any order, any of the given
  // fields). So "bucket red" matches "…red bucket…", not just the literal.
  const I = 'insensitive' as const
  const terms = q.split(/\s+/).filter(Boolean).slice(0, 8)
  const allTerms = (...fields: ('title' | 'notes' | 'body' | 'name' | 'location' | 'transcript' | 'textNote')[]) =>
    terms.map(t => ({ OR: fields.map(f => ({ [f]: { contains: t, mode: I } })) }))

  const [reminders, thoughts, items, lists, captures, events] = await Promise.all([
    db.reminder.findMany({
      where: { completed: false, AND: [visible.reminder(session.userId), { OR: [{ pendingAction: null }, { pendingAction: { not: 'delete' } }] }, ...allTerms('title', 'notes')] },
      select: { id: true, title: true, list: { select: { name: true } } },
      orderBy: { createdAt: 'desc' }, take: PER,
    }),
    db.thought.findMany({
      // each term: matches the body OR is an exact tag
      where: { archived: false, AND: [visible.thought(session.userId), ...terms.map(t => ({ OR: [{ body: { contains: t, mode: I } }, { tags: { has: t } }] }))] },
      select: { id: true, body: true }, orderBy: { createdAt: 'desc' }, take: PER,
    }),
    db.checklistItem.findMany({
      where: { list: { dismissed: false }, AND: [visible.checklistItem(session.userId), ...allTerms('title')] },
      select: { id: true, title: true, list: { select: { id: true, name: true } } }, take: PER,
    }),
    db.checklist.findMany({
      where: { dismissed: false, AND: [visible.checklist(session.userId), ...allTerms('name')] },
      select: { id: true, name: true }, take: 4,
    }),
    db.capture.findMany({
      where: { AND: [visible.capture(session.userId), ...allTerms('transcript', 'textNote')] },
      select: { id: true, transcript: true, textNote: true }, orderBy: { createdAt: 'desc' }, take: 5,
    }),
    db.calendarEvent.findMany({
      where: { AND: [visible.calendarEvent(session.userId), ...allTerms('title', 'notes', 'location')] },
      select: { id: true, title: true, startsAt: true }, orderBy: { startsAt: 'asc' }, take: 5,
    }),
  ])

  const results: Hit[] = [
    ...reminders.map(r => ({ type: 'reminder' as const, id: r.id, title: r.title, sub: r.list?.name ?? null, href: '/reminders' })),
    ...thoughts.map(t => ({ type: 'thought' as const, id: t.id, title: clip(t.body), sub: null, href: '/thoughts' })),
    ...items.map(i => ({ type: 'item' as const, id: i.id, title: i.title, sub: i.list?.name ?? null, href: `/list/${i.list?.id}` })),
    ...lists.map(l => ({ type: 'list' as const, id: l.id, title: l.name, sub: 'List', href: `/list/${l.id}` })),
    ...captures.map(c => ({ type: 'capture' as const, id: c.id, title: clip(c.transcript || c.textNote || '(no transcript)'), sub: 'Capture', href: `/capture/${c.id}` })),
    ...events.map(e => ({ type: 'event' as const, id: e.id, title: e.title, sub: new Date(e.startsAt).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }), href: '/' })),
  ]

  return NextResponse.json({ results })
}
