/**
 * Route-level tests for audit module — Fastify inject.
 */

import Fastify from 'fastify';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const repoMock = {
  create: vi.fn(),
  query: vi.fn(),
  getStats: vi.fn(),
};

vi.mock('./repository.js', () => repoMock);
vi.mock('../../lib/request-context.js', () => ({
  getRequestProductId: () => 'lysnrai',
}));

async function buildApp() {
  const { auditRoutes } = await import('./routes.js');
  const app = Fastify({ logger: false });
  await app.register(auditRoutes, { prefix: '/api' });
  return app;
}

describe('auditRoutes', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('POST /audit accepts valid payload (fire-and-forget)', async () => {
    repoMock.create.mockResolvedValue(undefined);
    const app = await buildApp();

    const res = await app.inject({
      method: 'POST',
      url: '/api/audit',
      payload: {
        userId: 'user_1',
        action: 'item.created',
        category: 'tracker',
        details: { itemId: 'trk_1' },
      },
    });

    expect(res.statusCode).toBe(202);
    expect(JSON.parse(res.body).accepted).toBe(true);
    expect(repoMock.create).toHaveBeenCalled();
  });

  it('POST /audit preserves source timestamp when provided', async () => {
    repoMock.create.mockResolvedValue(undefined);
    const app = await buildApp();

    const res = await app.inject({
      method: 'POST',
      url: '/api/audit',
      payload: {
        userId: 'user_1',
        action: 'tool_executed',
        category: 'agent',
        timestamp: '2026-04-04T17:45:00.000Z',
        details: { eventId: 'evt_cowork_1', taskId: 'task_1' },
      },
    });

    expect(res.statusCode).toBe(202);
    expect(repoMock.create).toHaveBeenCalledWith(
      expect.objectContaining({
        timestamp: '2026-04-04T17:45:00.000Z',
      })
    );
  });

  it('POST /audit returns 400 on invalid payload', async () => {
    const app = await buildApp();

    const res = await app.inject({
      method: 'POST',
      url: '/api/audit',
      payload: { action: '' },
    });

    expect(res.statusCode).toBe(400);
  });

  it('GET /audit returns records', async () => {
    repoMock.query.mockResolvedValue([{ id: 'aud_1', action: 'item.created' }]);
    const app = await buildApp();

    const res = await app.inject({
      method: 'GET',
      url: '/api/audit?userId=user_1&days=7&limit=10&offset=0',
    });

    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.records).toHaveLength(1);
    expect(data.count).toBe(1);
  });

  it('GET /audit returns 400 for invalid query', async () => {
    const app = await buildApp();

    const res = await app.inject({ method: 'GET', url: '/api/audit?days=0' });

    expect(res.statusCode).toBe(400);
  });

  it('GET /audit/stats returns stats for given days', async () => {
    repoMock.getStats.mockResolvedValue({ item_created: 3, login: 5 });
    const app = await buildApp();

    const res = await app.inject({ method: 'GET', url: '/api/audit/stats?days=14' });

    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.days).toBe(14);
    expect(data.stats.item_created).toBe(3);
  });
});
