/**
 * Commission Config Property Tests
 * **Feature: invitation-commission-system, Property 7: Default commission rate**
 */

const fc = require('fast-check');

// Mock the Config model
jest.mock('../models/Config', () => ({
  findOne: jest.fn(),
  create: jest.fn(),
}));

const Config = require('../models/Config');
const commissionConfigService = require('../services/commissionConfigService');

describe('Commission Config Service - Property Tests', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  /**
   * **Feature: invitation-commission-system, Property 7: Default commission rate**
   * *For any* new system without commission_rate config, the default rate should be 0.02 (2%).
   * **Validates: Requirements 3.1**
   */
  describe('Property 7: Default commission rate', () => {
    it('should return default rate 0.02 when no config exists', async () => {
      // Arrange: No config in database
      Config.findOne.mockResolvedValue(null);

      // Act
      const rate = await commissionConfigService.getCommissionRate();

      // Assert
      expect(rate).toBe(0.02);
    });

    it('should return default rate when config value is invalid', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.oneof(
            fc.constant('invalid'),
            fc.constant(''),
            fc.constant(null),
            fc.double({ min: -100, max: -0.01 }), // negative values
            fc.double({ min: 1.01, max: 100 }), // values > 1
          ),
          async (invalidValue) => {
            // Arrange: Config with invalid value
            Config.findOne.mockResolvedValue({
              key: 'commission_rate',
              value: String(invalidValue),
            });

            // Act
            const rate = await commissionConfigService.getCommissionRate();

            // Assert: Should return default rate for invalid values
            expect(rate).toBe(0.02);
          }
        ),
        { numRuns: 100 }
      );
    });

    it('should return stored rate when config value is valid', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.double({ min: 0, max: 1, noNaN: true }),
          async (validRate) => {
            // Arrange: Config with valid value
            Config.findOne.mockResolvedValue({
              key: 'commission_rate',
              value: String(validRate),
            });

            // Act
            const rate = await commissionConfigService.getCommissionRate();

            // Assert: Should return the stored rate
            expect(rate).toBeCloseTo(validRate, 10);
          }
        ),
        { numRuns: 100 }
      );
    });
  });

  /**
   * Property: Commission rate validation
   * *For any* rate value, setCommissionRate should only accept values between 0 and 1.
   * **Validates: Requirements 3.2**
   */
  describe('Commission rate validation', () => {
    it('should reject invalid rate values', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.oneof(
            fc.double({ min: -100, max: -0.001, noNaN: true }),
            fc.double({ min: 1.001, max: 100, noNaN: true }),
          ),
          async (invalidRate) => {
            // Act & Assert
            await expect(
              commissionConfigService.setCommissionRate(invalidRate)
            ).rejects.toThrow('Invalid commission rate');
          }
        ),
        { numRuns: 100 }
      );
    });

    it('should accept valid rate values between 0 and 1', async () => {
      await fc.assert(
        fc.asyncProperty(
          fc.double({ min: 0, max: 1, noNaN: true }),
          async (validRate) => {
            // Arrange
            Config.findOne.mockResolvedValue(null);
            Config.create.mockResolvedValue({
              key: 'commission_rate',
              value: String(validRate),
              updatedAt: new Date(),
            });

            // Act
            const result = await commissionConfigService.setCommissionRate(validRate);

            // Assert
            expect(result.value).toBeCloseTo(validRate, 10);
          }
        ),
        { numRuns: 100 }
      );
    });
  });
});
