import { ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { lastValueFrom, of } from 'rxjs';
import { AuditInterceptor } from './audit.interceptor';
import { AuditService } from './audit.service';

describe('AuditInterceptor', () => {
  const createContext = (request: Record<string, any>) =>
    ({
      getHandler: jest.fn(),
      switchToHttp: () => ({ getRequest: () => request }),
    }) as unknown as ExecutionContext;

  it('usa el id de la respuesta al auditar una creación', async () => {
    const auditService = { log: jest.fn().mockResolvedValue(undefined) };
    const reflector = { get: jest.fn().mockReturnValue('compra') };
    const interceptor = new AuditInterceptor(
      auditService as unknown as AuditService,
      reflector as unknown as Reflector,
    );
    const context = createContext({
      method: 'POST',
      params: {},
      headers: {},
      user: { id: 'user-1', empresa_id: 'empresa-1' },
      ip: '127.0.0.1',
    });

    await lastValueFrom(interceptor.intercept(context, { handle: () => of({ id: 'compra-1' }) }));

    expect(auditService.log).toHaveBeenCalledWith(
      expect.objectContaining({
        empresa_id: 'empresa-1',
        user_id: 'user-1',
        action: 'CREATE',
        entity_type: 'compra',
        entity_id: 'compra-1',
      }),
    );
  });

  it('prioriza el id de la ruta al auditar una actualización', async () => {
    const auditService = { log: jest.fn().mockResolvedValue(undefined) };
    const reflector = { get: jest.fn().mockReturnValue('gasto') };
    const interceptor = new AuditInterceptor(
      auditService as unknown as AuditService,
      reflector as unknown as Reflector,
    );
    const context = createContext({
      method: 'PATCH',
      params: { id: 'gasto-ruta' },
      route: { path: ':id/anular' },
      headers: {},
      user: { id: 'user-1', empresa_id: 'empresa-1' },
    });

    await lastValueFrom(interceptor.intercept(context, { handle: () => of({ id: 'otro-id' }) }));

    expect(auditService.log).toHaveBeenCalledWith(
      expect.objectContaining({
        action: 'CHANGE_STATUS',
        entity_type: 'gasto',
        entity_id: 'gasto-ruta',
      }),
    );
  });

  it('clasifica un PATCH de edición como UPDATE', async () => {
    const auditService = { log: jest.fn().mockResolvedValue(undefined) };
    const reflector = { get: jest.fn().mockReturnValue('compra') };
    const interceptor = new AuditInterceptor(
      auditService as unknown as AuditService,
      reflector as unknown as Reflector,
    );
    const context = createContext({
      method: 'PATCH',
      params: { id: 'compra-1' },
      route: { path: ':id' },
      headers: {},
      user: { id: 'user-1', empresa_id: 'empresa-1' },
    });

    await lastValueFrom(interceptor.intercept(context, { handle: () => of({ id: 'compra-1' }) }));

    expect(auditService.log).toHaveBeenCalledWith(
      expect.objectContaining({
        action: 'UPDATE',
        entity_type: 'compra',
        entity_id: 'compra-1',
      }),
    );
  });
});
