import { AssemblyMonitoringService } from './assembly-monitoring.service';
import type { AssemblyMonitoringRepository } from './assembly-monitoring.repository';
import type { PinoLogger } from 'nestjs-pino';
import { assemblyServiceFixtures } from '@test-fixtures/monitoring/assembly/scenario.fixture';

describe('AssemblyMonitoringService', () => {
  let service: AssemblyMonitoringService;
  let repository: jest.Mocked<AssemblyMonitoringRepository>;
  let logger: jest.Mocked<PinoLogger>;
  let findRealtimeData: jest.Mock;
  let findDailyData: jest.Mock;
  let findProcesses: jest.Mock;
  let findWaitingProcesses: jest.Mock;
  let findUnitList: jest.Mock;
  let findUnitDetail: jest.Mock;
  let warn: jest.Mock;

  beforeEach(() => {
    findRealtimeData = jest.fn();
    findDailyData = jest.fn();
    findProcesses = jest.fn();
    findWaitingProcesses = jest.fn();
    findUnitList = jest.fn();
    findUnitDetail = jest.fn();
    warn = jest.fn();

    repository = {
      findRealtimeData,
      findDailyData,
      findProcesses,
      findWaitingProcesses,
      findUnitList,
      findUnitDetail,
    } as unknown as jest.Mocked<AssemblyMonitoringRepository>;

    logger = {
      setContext: jest.fn(),
      debug: jest.fn(),
      warn,
    } as unknown as jest.Mocked<PinoLogger>;

    service = new AssemblyMonitoringService(repository, logger);
  });

  afterEach(() => {
    jest.clearAllMocks();
    jest.useRealTimers();
  });

  it('applies default factUnit for realtime and returns grouped result', async () => {
    findRealtimeData.mockResolvedValue(assemblyServiceFixtures.realtimeResult);

    const result = await service.findRealtimeData(
      assemblyServiceFixtures.realtimeQuery,
    );

    expect(findRealtimeData).toHaveBeenCalledWith(
      assemblyServiceFixtures.realtimeExpectedQuery,
    );
    expect(result.processes.driveUnitAssembly).toEqual(
      assemblyServiceFixtures.emptyList,
    );
    expect(result.inactiveWorkers).toEqual(
      assemblyServiceFixtures.emptyInactiveWorkers,
    );
  });

  it('applies default factUnit for daily query', async () => {
    findDailyData.mockResolvedValue(assemblyServiceFixtures.emptyList);

    const result = await service.findDailyData(
      assemblyServiceFixtures.dailyQuery,
    );

    expect(findDailyData).toHaveBeenCalledWith(
      assemblyServiceFixtures.dailyExpectedQuery,
    );
    expect(result.processes.corePumpAssembly).toEqual(
      assemblyServiceFixtures.emptyList,
    );
  });

  it('transforms process status rows', async () => {
    findProcesses.mockResolvedValue(assemblyServiceFixtures.processStatusRows);

    const result = await service.findProcesses(
      assemblyServiceFixtures.processesQuery,
    );

    expect(result.processes.driveUnitAssembly).toHaveLength(1);
    expect(result.processes.driveUnitAssembly[0]).toMatchObject(
      assemblyServiceFixtures.processStatusExpectedMatch,
    );
  });

  it('uses waiting status mapping for waiting processes', async () => {
    findWaitingProcesses.mockResolvedValue(
      assemblyServiceFixtures.waitingProcessRows,
    );

    const result = await service.findWaitingProcesses(
      assemblyServiceFixtures.processesQuery,
    );

    expect(result.processes.driveUnitAssembly).toHaveLength(1);
    expect(result.processes.driveUnitAssembly[0]).toMatchObject(
      assemblyServiceFixtures.waitingProcessExpectedMatch,
    );
  });

  it('applies defaults for unit list query', async () => {
    jest.useFakeTimers().setSystemTime(assemblyServiceFixtures.unitListNow);
    findUnitList.mockResolvedValue(assemblyServiceFixtures.emptyList);

    await service.findUnitList(assemblyServiceFixtures.unitListQuery);

    expect(findUnitList).toHaveBeenCalledWith(
      assemblyServiceFixtures.unitListExpectedQuery,
    );
  });

  it('returns null when unit detail has no rows', async () => {
    findUnitDetail.mockResolvedValue(assemblyServiceFixtures.emptyList);

    const result = await service.findUnitDetail(
      assemblyServiceFixtures.unitDetailQuery,
    );

    expect(findUnitDetail).toHaveBeenCalledWith(
      assemblyServiceFixtures.unitDetailExpectedQuery,
    );
    expect(result).toBeNull();
  });

  it('warns when multiple tracks are returned', async () => {
    findUnitDetail.mockResolvedValue(
      assemblyServiceFixtures.unitDetailMultiTrackRows,
    );

    const result = await service.findUnitDetail(
      assemblyServiceFixtures.unitDetailMultiTrackQuery,
    );

    expect(warn).toHaveBeenCalled();
    expect(result?.prodPlanSeq).toBe(
      assemblyServiceFixtures.unitDetailMultiTrackExpectedProdPlanSeq,
    );
  });
});
