import {
  searchEntities as searchModuleEntities,
  type Hit,
  type SearchRegistry,
  type SearchResult,
} from '@platform-modules/search'
import type { Db } from '@zync/db/queries'
import {
  searchCustomers,
  searchExpenses,
  searchKbArticles,
  searchProjects,
  searchSupportTickets,
  searchTasks,
  searchTeamMembers,
} from '../../../../../packages/db/src/search/entity-queries'

export type PlatformSearchEntityType =
  | 'task'
  | 'project'
  | 'customer'
  | 'expense'
  | 'kb_article'
  | 'support_ticket'
  | 'team_member'

export type PlatformSearchContext = {
  db: Db
  tenantId: string
  userId: string
  isContractor: boolean
}

export type PlatformSearchParams = {
  query: string
  ctx: PlatformSearchContext
  entityTypes?: PlatformSearchEntityType[]
  limit: number
  cursor?: string | null
  registry?: SearchRegistry<PlatformSearchContext>
}

function toHit(
  entityType: PlatformSearchEntityType,
  item: {
    id: string
    primary?: string | null
    label: string
    highlight?: string | null
  },
): Hit {
  return {
    entityType,
    id: item.id,
    rank: 0,
    title: item.primary ?? item.label,
    ...(item.highlight ? { snippetHtml: item.highlight } : {}),
  }
}

async function queryTasks(query: string, ctx: PlatformSearchContext, limit: number, offset: number) {
  const result = await searchTasks(
    ctx.db,
    ctx.tenantId,
    ctx.userId,
    ctx.isContractor,
    query,
    limit,
    offset,
  )
  return {
    hits: result.items.map((item) => toHit('task', item)),
    total: result.total,
  }
}

async function queryProjects(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchProjects(ctx.db, ctx.tenantId, query, limit, offset)
  return {
    hits: result.items.map((item) => toHit('project', item)),
    total: result.total,
  }
}

async function queryCustomers(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchCustomers(ctx.db, ctx.tenantId, query, limit, offset)
  return {
    hits: result.items.map((item) => toHit('customer', item)),
    total: result.total,
  }
}

async function queryExpenses(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchExpenses(ctx.db, ctx.tenantId, query, limit, offset)
  return {
    hits: result.items.map((item) => toHit('expense', item)),
    total: result.total,
  }
}

async function queryKbArticles(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchKbArticles(
    ctx.db,
    ctx.tenantId,
    ctx.isContractor ? 'CONTRACTOR' : 'OWNER',
    query,
    limit,
    offset,
  )
  return {
    hits: result.items.map((item) => toHit('kb_article', item)),
    total: result.total,
  }
}

async function querySupportTickets(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchSupportTickets(ctx.db, ctx.tenantId, query, limit, offset)
  return {
    hits: result.items.map((item) => toHit('support_ticket', item)),
    total: result.total,
  }
}

async function queryTeamMembers(
  query: string,
  ctx: PlatformSearchContext,
  limit: number,
  offset: number,
) {
  const result = await searchTeamMembers(ctx.db, ctx.tenantId, query, limit, offset)
  return {
    hits: result.items.map((item) => toHit('team_member', item)),
    total: result.total,
  }
}

export function createPlatformSearchRegistry(): SearchRegistry<PlatformSearchContext> {
  return {
    task: (query, ctx, window) => queryTasks(query, ctx, window.limit, window.offset),
    project: (query, ctx, window) => queryProjects(query, ctx, window.limit, window.offset),
    customer: (query, ctx, window) => queryCustomers(query, ctx, window.limit, window.offset),
    expense: (query, ctx, window) => queryExpenses(query, ctx, window.limit, window.offset),
    kb_article: (query, ctx, window) => queryKbArticles(query, ctx, window.limit, window.offset),
    support_ticket: (query, ctx, window) =>
      querySupportTickets(query, ctx, window.limit, window.offset),
    team_member: (query, ctx, window) => queryTeamMembers(query, ctx, window.limit, window.offset),
  }
}

export async function runPlatformSearch(params: PlatformSearchParams): Promise<SearchResult> {
  return searchModuleEntities(params.registry ?? createPlatformSearchRegistry(), {
    query: params.query,
    ctx: params.ctx,
    entityTypes: params.entityTypes,
    limit: params.limit,
    cursor: params.cursor ?? null,
  })
}
