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

const mockListAuditLog = vi.fn()
const mockFetchAuditLogForExport = vi.fn()

let mockSession: {
  type: 'user'
  sub: string
  tid: string
  role: string
}

vi.mock('../src/middleware/auth', () => ({
  authMiddleware: async (c: { set: (key: string, value: unknown) => void }, next: () => Promise<void>) => {
    c.set('db', {})
    c.set('session', mockSession)
    await next()
  },
}))

vi.mock('@zync/db/queries', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@zync/db/queries')>()
  return {
    ...actual,
    listAuditLog: (...args: unknown[]) => mockListAuditLog(...args),
    fetchAuditLogForExport: (...args: unknown[]) => mockFetchAuditLogForExport(...args),
  }
})

import { auditLogRoutes } from '../src/routes/audit-log'

function buildApp() {
  const app = new Hono<AppEnv>()
  app.route('/api/audit-log', auditLogRoutes)
  return app
}

const mockEnv = {
  DB: { connectionString: 'postgresql://test:test@localhost/test' },
} as AppEnv['Bindings']

describe('audit log routes', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockSession = {
      type: 'user',
      sub: '00000000-0000-4000-8000-000000000001',
      tid: '00000000-0000-4000-8000-000000000010',
      role: 'OWNER',
    }
    mockListAuditLog.mockResolvedValue({
      items: [],
      next_cursor: null,
      has_more: false,
    })
    mockFetchAuditLogForExport.mockResolvedValue([])
  })

  it('accepts ISO datetimes on GET /api/audit-log', async () => {
    const res = await buildApp().request(
      '/api/audit-log?from=2026-05-01T00:00:00.000Z&to=2026-05-31T23:59:59.000Z',
      { method: 'GET' },
      { Bindings: mockEnv },
    )

    expect(res.status).toBe(200)
    expect(mockListAuditLog).toHaveBeenCalledWith(
      {},
      mockSession.tid,
      expect.objectContaining({
        from: '2026-05-01T00:00:00.000Z',
        to: '2026-05-31T23:59:59.000Z',
      }),
    )
  })

  it('accepts unix timestamps on GET /api/audit-log', async () => {
    const res = await buildApp().request(
      '/api/audit-log?from=1746057600&to=1748735999',
      { method: 'GET' },
      { Bindings: mockEnv },
    )

    expect(res.status).toBe(200)
    expect(mockListAuditLog).toHaveBeenCalledWith(
      {},
      mockSession.tid,
      expect.objectContaining({
        from: '1746057600',
        to: '1748735999',
      }),
    )
  })

  it('allows MEMBER export from reports scope (own-actions only)', async () => {
    mockSession.role = 'MEMBER'

    const res = await buildApp().request(
      '/api/audit-log/export?scope=reports',
      { method: 'GET' },
      { Bindings: mockEnv },
    )

    expect(res.status).toBe(200)
    expect(mockFetchAuditLogForExport).toHaveBeenCalled()
  })
})
