import {pickPresent} from '@crumbs/core/collections'
import {MAX_PAGE_SIZE, SearchQuerySchema} from '@crumbs/core/schemas'
import {and, desc, eq, ilike, ne, or} from 'drizzle-orm'
import {Hono} from 'hono'

import {type GuardedVars} from '../auth/middleware'
import {db, schema} from '../db/client'
import {escapeLike} from '../lib/sql'
import {validate} from '../lib/validate'
import {notBlockedByViewer} from '../services/blocks'
import {crumbJoinedSelect, toCrumbResponses} from '../services/crumbs'
import {
  hydrateProfileRows,
  profileRowColumns,
} from '../services/friends'
import {listTrailSummaries} from '../services/trails'

const search = new Hono<{Variables: GuardedVars}>().get(
  '/',
  validate('query', SearchQuerySchema),
  async (c) => {
    const user = c.get('user')
    const {q} = c.req.valid('query')
    const pattern = `%${escapeLike(q)}%`

    const [crumbRows, trailResult, userRows] = await Promise.all([
      crumbJoinedSelect()
        .where(
          and(
            eq(schema.crumbs.authorId, user.id),
            or(
              ilike(schema.crumbs.name, pattern),
              ilike(schema.crumbs.note, pattern),
              ilike(schema.places.name, pattern),
              ilike(schema.places.category, pattern),
              ilike(schema.places.address, pattern),
            ),
          ),
        )
        .orderBy(desc(schema.crumbs.createdAt))
        .limit(100),
      listTrailSummaries({
        subjectId: user.id,
        viewerId: user.id,
        extraWhere: ilike(schema.trails.name, pattern),
        limit: MAX_PAGE_SIZE,
      }),
      db
        .select(profileRowColumns)
        .from(schema.users)
        .where(
          and(
            ne(schema.users.id, user.id),
            ilike(schema.users.handle, pattern),
            // a block (either direction) hides each user from the other
            notBlockedByViewer(schema.users.id, user.id),
          ),
        )
        .orderBy(schema.users.handle)
        .limit(50),
    ])

    const [crumbs, profiles] = await Promise.all([
      toCrumbResponses(crumbRows),
      hydrateProfileRows(user.id, userRows),
    ])

    return c.json({
      crumbs,
      trails: trailResult.trails,
      users: pickPresent(
        profiles,
        userRows.map((r) => r.id),
      ),
    })
  },
)

export default search
