import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'
import type { AppEnv } from '../src/types'

const mockDeleteDependency = vi.fn()
const mockGetTask = vi.fn()
const mockBumpProjectRevision = vi.fn()

vi.mock('../src/middleware/guards', () => ({
  requirePermission: () => async (_c: unknown, next: () => Promise<void>) => next(),
  requireTier: () => async (_c: unknown, next: () => Promise<void>) => next(),
}))

vi.mock('@zync/db/queries', () => ({
  getDependencies: vi.fn(),
  insertDependency: vi.fn(),
  deleteDependency: (...args: unknown[]) => mockDeleteDependency(...args),
  assertSameProject: vi.fn(),
  wouldCreateCycle: vi.fn(),
  bumpProjectRevision: (...args: unknown[]) => mockBumpProjectRevision(...args),
  DuplicateDependencyError: class DuplicateDependencyError extends Error {},
  CrossProjectDependencyError: class CrossProjectDependencyError extends Error {},
  getTask: (...args: unknown[]) => mockGetTask(...args),
}))

function appFor() {
  const app = new Hono<AppEnv>()
  app.use('*', async (c, next) => {
    c.set('session', {
      type: 'user',
      sub: 'user-1',
      tid: 'tenant-1',
      role: 'OWNER',
      permissions: ['projects:write'],
    })
    c.set('db', {})
    await next()
  })
  return app
}

describe('task dependency cache invalidation', () => {
  const taskId = '11111111-1111-4111-8111-111111111111'
  const dependencyId = '22222222-2222-4222-8222-222222222222'
  const projectId = '33333333-3333-4333-8333-333333333333'

  beforeEach(() => {
    vi.clearAllMocks()
    mockDeleteDependency.mockResolvedValue(undefined)
    mockGetTask.mockResolvedValue({
      id: taskId,
      project_id: projectId,
    })
    mockBumpProjectRevision.mockResolvedValue(undefined)
  })

  it('bumps the critical-path revision after deleting a dependency', async () => {
    const { taskDependenciesRoute } = await import('../src/routes/task-dependencies')
    const app = appFor()
    app.route('/api/tasks', taskDependenciesRoute)

    const res = await app.request(
      `/api/tasks/${taskId}/dependencies/${dependencyId}`,
      { method: 'DELETE' },
      { KV: {} } as AppEnv['Bindings'],
    )

    expect(res.status).toBe(204)
    expect(mockDeleteDependency).toHaveBeenCalledWith({}, 'tenant-1', dependencyId)
    expect(mockGetTask).toHaveBeenCalledWith({}, 'tenant-1', taskId)
    expect(mockBumpProjectRevision).toHaveBeenCalledWith(
      { KV: {} },
      'tenant-1',
      projectId,
    )
  })
})
