import { Test } from '@nestjs/testing';
import { ValidationPipe } from '@nestjs/common';
import type { INestApplication } from '@nestjs/common';
import request from 'supertest';
import { InventoryMonitoringController } from './inventory-monitoring.controller';
import { InventoryMonitoringService } from './inventory-monitoring.service';
import { ResponseInterceptor } from 'src/common/interceptors/response.interceptor';
import { GlobalExceptionFilter } from 'src/common/filters/global-exception.filter';
import { Logger, PinoLogger } from 'nestjs-pino';
import type { Server } from 'http';
import { inventoryControllerFixtures } from '@test-fixtures/monitoring/inventory/scenario.fixture';

describe('InventoryMonitoringController (integration)', () => {
  let app: INestApplication;
  const inventoryService = {
    findInventoryList: jest.fn(),
  };

  const loggerStub = {
    setContext: jest.fn(),
    info: jest.fn(),
    debug: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
  };

  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      controllers: [InventoryMonitoringController],
      providers: [
        ResponseInterceptor,
        { provide: InventoryMonitoringService, useValue: inventoryService },
        { provide: PinoLogger, useValue: loggerStub },
        { provide: Logger, useValue: loggerStub },
      ],
    }).compile();

    app = moduleRef.createNestApplication();
    app.useGlobalPipes(new ValidationPipe({ transform: true }));
    app.useGlobalFilters(
      new GlobalExceptionFilter(loggerStub as unknown as Logger),
    );
    app.useGlobalInterceptors(app.get(ResponseInterceptor));
    await app.init();
  });

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

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('wraps successful responses with standard format', async () => {
    inventoryService.findInventoryList.mockResolvedValue(
      inventoryControllerFixtures.listResponse,
    );

    const server = app.getHttpServer() as Server;
    const response = await request(server)
      .get(inventoryControllerFixtures.listPath)
      .expect(inventoryControllerFixtures.okStatusCode);

    expect(response.body.success).toBe(true);
    expect(response.body.data).toEqual(
      inventoryControllerFixtures.listResponse,
    );
    expect(response.body.meta).toEqual(
      expect.objectContaining(inventoryControllerFixtures.listMeta),
    );
  });

  it('returns standard error format on validation errors', async () => {
    const server = app.getHttpServer() as Server;
    const response = await request(server)
      .get(inventoryControllerFixtures.missingFromPath)
      .expect(inventoryControllerFixtures.badRequestStatusCode);

    expect(inventoryService.findInventoryList).not.toHaveBeenCalled();

    expect(response.body.success).toBe(false);
    expect(response.body.error).toEqual(
      expect.objectContaining(inventoryControllerFixtures.badRequestError),
    );
    expect(String(response.body.error.message)).toContain(
      inventoryControllerFixtures.missingFromKey,
    );
    expect(response.body.meta).toEqual(
      expect.objectContaining(inventoryControllerFixtures.missingFromMeta),
    );
  });
});
