import { describe, it, expect, vi, afterEach } from 'vitest';
import Fastify from 'fastify';
import type { FastifyInstance } from 'fastify';
import { registerAuditHook } from '../src/middleware/audit.js';

let app: FastifyInstance;

afterEach(async () => {
  if (app) await app.close();
});

describe('audit middleware', () => {
  it('logs mutating requests from authenticated users', async () => {
    const createAuditLog = vi.fn(async () => {});
    app = Fastify({ logger: false });

    // Simulate authenticated request
    app.addHook('preHandler', async (request) => {
      request.userId = 'user-1';
    });

    registerAuditHook(app, { createAuditLog });

    app.post('/api/v1/servers', async () => ({ ok: true }));
    await app.ready();

    await app.inject({ method: 'POST', url: '/api/v1/servers', payload: {} });

    expect(createAuditLog).toHaveBeenCalledOnce();
    expect(createAuditLog).toHaveBeenCalledWith(expect.objectContaining({
      userId: 'user-1',
      action: 'CREATE',
      resource: 'servers',
    }));
  });

  it('does not log GET requests', async () => {
    const createAuditLog = vi.fn(async () => {});
    app = Fastify({ logger: false });

    app.addHook('preHandler', async (request) => {
      request.userId = 'user-1';
    });

    registerAuditHook(app, { createAuditLog });
    app.get('/api/v1/servers', async () => []);
    await app.ready();

    await app.inject({ method: 'GET', url: '/api/v1/servers' });
    expect(createAuditLog).not.toHaveBeenCalled();
  });

  it('does not log unauthenticated requests', async () => {
    const createAuditLog = vi.fn(async () => {});
    app = Fastify({ logger: false });

    registerAuditHook(app, { createAuditLog });
    app.post('/api/v1/servers', async () => ({ ok: true }));
    await app.ready();

    await app.inject({ method: 'POST', url: '/api/v1/servers', payload: {} });
    expect(createAuditLog).not.toHaveBeenCalled();
  });

  it('maps DELETE method to DELETE action', async () => {
    const createAuditLog = vi.fn(async () => {});
    app = Fastify({ logger: false });

    app.addHook('preHandler', async (request) => {
      request.userId = 'user-1';
    });

    registerAuditHook(app, { createAuditLog });
    app.delete('/api/v1/servers/:id', async () => ({ ok: true }));
    await app.ready();

    await app.inject({ method: 'DELETE', url: '/api/v1/servers/srv-123' });
    expect(createAuditLog).toHaveBeenCalledWith(expect.objectContaining({
      action: 'DELETE',
      resource: 'servers',
      resourceId: 'srv-123',
    }));
  });

  it('maps PUT/PATCH to UPDATE action', async () => {
    const createAuditLog = vi.fn(async () => {});
    app = Fastify({ logger: false });

    app.addHook('preHandler', async (request) => {
      request.userId = 'user-1';
    });

    registerAuditHook(app, { createAuditLog });
    app.put('/api/v1/servers/:id', async () => ({ ok: true }));
    await app.ready();

    await app.inject({ method: 'PUT', url: '/api/v1/servers/srv-1', payload: {} });
    expect(createAuditLog).toHaveBeenCalledWith(expect.objectContaining({
      action: 'UPDATE',
    }));
  });
});
