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

const { mockCheckWorkspaceAccess, dbState } = vi.hoisted(() => ({
  mockCheckWorkspaceAccess: vi.fn(),
  dbState: { results: [] as any[][] },
}))

function makeChain() {
  const chain: any = {}
  chain.from = vi.fn(() => chain)
  chain.where = vi.fn(() => chain)
  chain.limit = vi.fn(() => Promise.resolve(dbState.results.shift() ?? []))
  return chain
}

vi.mock('@sim/db', () => ({
  db: { select: vi.fn(() => makeChain()) },
}))

vi.mock('@sim/db/schema', () => ({
  credentialTypeEnum: {
    enumValues: ['oauth', 'env_workspace', 'env_personal', 'service_account'],
  },
  credential: {
    id: 'credential.id',
    workspaceId: 'credential.workspaceId',
    type: 'credential.type',
  },
  credentialMember: {
    credentialId: 'credentialMember.credentialId',
    userId: 'credentialMember.userId',
    status: 'credentialMember.status',
    role: 'credentialMember.role',
  },
}))

vi.mock('drizzle-orm', () => ({
  and: vi.fn((...args: unknown[]) => ({ and: args })),
  eq: vi.fn((a: unknown, b: unknown) => ({ eq: [a, b] })),
  inArray: vi.fn((a: unknown, b: unknown) => ({ inArray: [a, b] })),
}))

vi.mock('@/lib/workspaces/permissions/utils', () => ({
  checkWorkspaceAccess: mockCheckWorkspaceAccess,
}))

import { getCredentialActorContext } from '@/lib/credentials/access'

const workspaceAdminAccess = { hasAccess: true, canWrite: true, canAdmin: true }
const noWorkspaceAccess = { hasAccess: false, canWrite: false, canAdmin: false }

describe('getCredentialActorContext', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    dbState.results = []
  })

  it('treats an explicit credential admin membership as admin', async () => {
    dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], [{ role: 'admin' }]]
    mockCheckWorkspaceAccess.mockResolvedValue({ hasAccess: true, canWrite: true, canAdmin: false })

    const ctx = await getCredentialActorContext('c1', 'user1')

    expect(ctx.isAdmin).toBe(true)
  })

  it('derives credential admin from workspace admin for shared credentials', async () => {
    dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []]
    mockCheckWorkspaceAccess.mockResolvedValue(workspaceAdminAccess)

    const ctx = await getCredentialActorContext('c1', 'admin-user')

    expect(ctx.isAdmin).toBe(true)
  })

  it('does not derive credential admin on personal env credentials', async () => {
    dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'env_personal' }], []]
    mockCheckWorkspaceAccess.mockResolvedValue(workspaceAdminAccess)

    const ctx = await getCredentialActorContext('c1', 'admin-user')

    expect(ctx.isAdmin).toBe(false)
  })

  it('is not admin for a non-admin without membership', async () => {
    dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []]
    mockCheckWorkspaceAccess.mockResolvedValue({
      hasAccess: true,
      canWrite: false,
      canAdmin: false,
    })

    const ctx = await getCredentialActorContext('c1', 'reader-user')

    expect(ctx.isAdmin).toBe(false)
  })

  it('returns empty context when the credential does not exist', async () => {
    dbState.results = [[]]

    const ctx = await getCredentialActorContext('missing', 'user1')

    expect(ctx.credential).toBeNull()
    expect(ctx.isAdmin).toBe(false)
    expect(mockCheckWorkspaceAccess).not.toHaveBeenCalled()
  })

  it('exposes workspace access flags from checkWorkspaceAccess', async () => {
    dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []]
    mockCheckWorkspaceAccess.mockResolvedValue(noWorkspaceAccess)

    const ctx = await getCredentialActorContext('c1', 'outsider')

    expect(ctx.hasWorkspaceAccess).toBe(false)
    expect(ctx.canWriteWorkspace).toBe(false)
    expect(ctx.isAdmin).toBe(false)
  })
})
