import { Test, TestingModule } from '@nestjs/testing';
import { RecordEngagementUseCase } from './RecordEngagementUseCase';
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
import type { Logger } from '@core/shared/application';

describe('RecordEngagementUseCase', () => {
  let useCase: RecordEngagementUseCase;
  let engagementRepository: jest.Mocked<IEngagementRepository>;
  let logger: jest.Mocked<Logger>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        RecordEngagementUseCase,
        {
          provide: 'IEngagementRepository_TOKEN',
          useValue: {
            save: jest.fn(),
          },
        },
        {
          provide: 'Logger_TOKEN',
          useValue: {
            debug: jest.fn(),
            info: jest.fn(),
            error: jest.fn(),
          },
        },
      ],
    }).compile();

    useCase = module.get<RecordEngagementUseCase>(RecordEngagementUseCase);
    engagementRepository = module.get('IEngagementRepository_TOKEN');
    logger = module.get('Logger_TOKEN');
  });

  describe('execute', () => {
    it('should save the engagement event and return the eventId and engagementWeight', async () => {
      const input = {
        action: 'like' as any,
        entityType: 'race' as any,
        entityId: 'race-123',
        actorType: 'driver',
        sessionId: 'session-456',
        actorId: 'actor-789',
        metadata: { some: 'data' },
      };

      const mockEvent = {
        getEngagementWeight: jest.fn().mockReturnValue(10),
      };

      // Mock the create function to return the mock event
      const originalCreate = require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create;
      require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create = jest.fn().mockReturnValue(mockEvent);

      engagementRepository.save.mockResolvedValue(undefined);

      const result = await useCase.execute(input);

      expect(logger.debug).toHaveBeenCalledWith('Executing RecordEngagementUseCase', { input });
      expect(engagementRepository.save).toHaveBeenCalledWith(mockEvent);
      expect(logger.info).toHaveBeenCalledWith('Engagement recorded successfully', expect.objectContaining({ eventId: expect.any(String), input }));
      expect(result).toHaveProperty('eventId');
      expect(result).toHaveProperty('engagementWeight', 10);
      expect(typeof result.eventId).toBe('string');

      // Restore original
      require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create = originalCreate;
    });

    it('should handle errors and throw them', async () => {
      const input = {
        action: 'like' as any,
        entityType: 'race' as any,
        entityId: 'race-123',
        actorType: 'driver',
        sessionId: 'session-456',
      };

      const error = new Error('Save failed');
      engagementRepository.save.mockRejectedValue(error);

      await expect(useCase.execute(input)).rejects.toThrow('Save failed');
      expect(logger.error).toHaveBeenCalledWith('Error recording engagement', error, { input });
    });
  });
});