import { Test, TestingModule } from '@nestjs/testing';
import { FeatureFlagService } from './feature-flag.service';
import { FeatureFlagRepository } from './feature-flag.repository';
import { AppLoggerService } from 'src/common/services/logger.service';

describe('FeatureFlagService', () => {
  let service: FeatureFlagService;
  const mockRepository = { findActiveFlags: jest.fn(), findFlagByKey: jest.fn(), findFlagForProgramType: jest.fn() };
  const mockLogger = { log: jest.fn(), error: jest.fn() };

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

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        FeatureFlagService,
        { provide: FeatureFlagRepository, useValue: mockRepository },
        { provide: AppLoggerService, useValue: mockLogger },
      ],
    }).compile();

    service = module.get<FeatureFlagService>(FeatureFlagService);
  });

  describe('isFeatureEnabledForProgramType', () => {
    it('returns true when the resolved flag (program-type-scoped or global) is enabled', async () => {
      mockRepository.findFlagForProgramType.mockResolvedValue({ key: 'enableZoomLinksReport', flag: true });

      const result = await service.isFeatureEnabledForProgramType('enableZoomLinksReport', 5);

      expect(result).toBe(true);
      expect(mockRepository.findFlagForProgramType).toHaveBeenCalledWith('enableZoomLinksReport', 5);
    });

    it('returns false when the resolved flag is disabled', async () => {
      mockRepository.findFlagForProgramType.mockResolvedValue({ key: 'enableZoomLinksReport', flag: false });

      const result = await service.isFeatureEnabledForProgramType('enableZoomLinksReport', 5);

      expect(result).toBe(false);
    });

    it('returns false when no flag row exists at all for this key/program type', async () => {
      mockRepository.findFlagForProgramType.mockResolvedValue(null);

      const result = await service.isFeatureEnabledForProgramType('unknownKey', 5);

      expect(result).toBe(false);
    });
  });

  describe('areAllFeaturesEnabledForProgramType', () => {
    it('returns true only when every key resolves enabled', async () => {
      mockRepository.findFlagForProgramType.mockResolvedValue({ flag: true });

      const result = await service.areAllFeaturesEnabledForProgramType(['keyA', 'keyB'], 5);

      expect(result).toBe(true);
    });

    it('returns false and short-circuits on the first disabled key', async () => {
      mockRepository.findFlagForProgramType
        .mockResolvedValueOnce({ flag: true })
        .mockResolvedValueOnce({ flag: false });

      const result = await service.areAllFeaturesEnabledForProgramType(['keyA', 'keyB', 'keyC'], 5);

      expect(result).toBe(false);
      expect(mockRepository.findFlagForProgramType).toHaveBeenCalledTimes(2);
    });

    it('returns true for an empty key list (vacuously true)', async () => {
      const result = await service.areAllFeaturesEnabledForProgramType([], 5);

      expect(result).toBe(true);
      expect(mockRepository.findFlagForProgramType).not.toHaveBeenCalled();
    });
  });
});
