import { beforeEach, describe, expect, it, vi } from 'vitest'

const getEnabledModuleIds = vi.fn()

const searchTasks = vi.fn()
const searchProjects = vi.fn()
const searchCustomers = vi.fn()
const searchInvoices = vi.fn()
const searchReceipts = vi.fn()
const searchExpenses = vi.fn()
const searchVendors = vi.fn()
const searchLeads = vi.fn()
const searchProposals = vi.fn()
const searchContracts = vi.fn()
const searchContractors = vi.fn()
const searchKbArticles = vi.fn()
const searchSupportTickets = vi.fn()
const searchTeamMembers = vi.fn()

vi.mock('../src/queries/tenant-modules', () => ({
  getEnabledModuleIds,
}))

vi.mock('../src/search/entity-queries', () => ({
  encodeCursor: vi.fn(),
  decodeCursor: vi.fn(),
  searchTasks,
  searchProjects,
  searchCustomers,
  searchInvoices,
  searchReceipts,
  searchExpenses,
  searchVendors,
  searchLeads,
  searchProposals,
  searchContracts,
  searchContractors,
  searchKbArticles,
  searchSupportTickets,
  searchTeamMembers,
}))

const itemFor = (type: string) => ({
  id: `${type}-1`,
  type,
  label: `${type}: 1`,
  primary: `${type} primary`,
  secondary: null,
  badge: null,
  url: `/${type}/1`,
  highlight: null,
})

describe('searchEntities', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    getEnabledModuleIds.mockResolvedValue([
      'system',
      'tasks',
      'projects',
      'customers',
      'invoices',
      'expenses',
      'marketing',
      'kb',
      'crm',
    ])

    searchTasks.mockResolvedValue({ items: [itemFor('task')], total: 1 })
    searchProjects.mockResolvedValue({ items: [itemFor('project')], total: 1 })
    searchCustomers.mockResolvedValue({ items: [itemFor('customer')], total: 1 })
    searchInvoices.mockResolvedValue({ items: [itemFor('invoice')], total: 1 })
    searchReceipts.mockResolvedValue({ items: [itemFor('receipt')], total: 1 })
    searchExpenses.mockResolvedValue({ items: [itemFor('expense')], total: 1 })
    searchVendors.mockResolvedValue({ items: [itemFor('vendor')], total: 1 })
    searchLeads.mockResolvedValue({ items: [itemFor('lead')], total: 1 })
    searchProposals.mockResolvedValue({ items: [itemFor('proposal')], total: 1 })
    searchContracts.mockResolvedValue({ items: [itemFor('contract')], total: 1 })
    searchContractors.mockResolvedValue({ items: [itemFor('contractor')], total: 1 })
    searchKbArticles.mockResolvedValue({ items: [itemFor('kb_article')], total: 1 })
    searchSupportTickets.mockResolvedValue({ items: [itemFor('support_ticket')], total: 1 })
    searchTeamMembers.mockResolvedValue({ items: [itemFor('team_member')], total: 1 })
  })

  it('returns every enabled and permitted entity type instead of suppressing newer ones', async () => {
    const { searchEntities } = await import('../src/search/search-service')

    const result = await searchEntities({
      db: {} as never,
      tenantId: 'tenant-1',
      userId: 'user-1',
      role: 'OWNER',
      permissions: [
        'tasks:read',
        'projects:read',
        'customers:read',
        'invoices:read',
        'expenses:read',
        'marketing:read',
        'contracts:read',
        'payouts:read',
        'kb:read',
        'tickets:read',
        'users:read',
      ],
      query: 'alpha',
      limit: 5,
      types: ['lead', 'proposal', 'contract', 'contractor', 'support_ticket', 'vendor'],
      cursor: null,
    })

    expect(result.groups.map((group) => group.type)).toEqual([
      'vendor',
      'lead',
      'proposal',
      'contract',
      'contractor',
      'support_ticket',
    ])
    expect(searchLeads).toHaveBeenCalledOnce()
    expect(searchProposals).toHaveBeenCalledOnce()
    expect(searchContracts).toHaveBeenCalledOnce()
    expect(searchContractors).toHaveBeenCalledOnce()
    expect(searchSupportTickets).toHaveBeenCalledOnce()
    expect(searchVendors).toHaveBeenCalledOnce()
  })

  it('restricts contractors to tasks only even when other permissions are present', async () => {
    const { searchEntities } = await import('../src/search/search-service')

    const result = await searchEntities({
      db: {} as never,
      tenantId: 'tenant-1',
      userId: 'user-1',
      role: 'CONTRACTOR',
      permissions: ['tasks:read', 'customers:read', 'kb:read', 'team:read'],
      query: 'alpha',
      limit: 5,
      types: ['task', 'customer', 'kb_article', 'team_member'],
      cursor: null,
    })

    expect(result.groups.map((group) => group.type)).toEqual(['task'])
    expect(searchTasks).toHaveBeenCalledOnce()
    expect(searchCustomers).not.toHaveBeenCalled()
    expect(searchKbArticles).not.toHaveBeenCalled()
    expect(searchTeamMembers).not.toHaveBeenCalled()
  })
})
