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

/**
 * Property-Based Tests for Service Type Routing
 * Feature: service-appointment-forms, Property 7: Service Type Routing
 * Validates: Requirements 17.1
 * 
 * For any service selection, the system SHALL navigate to the correct 
 * form page based on the service type mapping.
 */

// Service type to page mapping (mirrors utils/service-routing.js)
const SERVICE_TYPE_MAP = {
  airfare: {
    category: 'travel',
    page: 'airfare-info-entry-page',
    path: '/pages/appointment/airfare-info-entry-page'
  },
  hotel: {
    category: 'accommodation',
    page: 'hotel-reservation-page',
    path: '/pages/appointment/hotel-reservation-page'
  },
  vip_lounge: {
    category: 'travel',
    page: 'vip-lounge-page',
    path: '/pages/appointment/vip-lounge-page'
  },
  airport_transfer: {
    category: 'travel',
    page: 'airport-transfer-page',
    path: '/pages/appointment/airport-transfer-page'
  },
  rail_ticket: {
    category: 'travel',
    page: 'rail-ticket-page',
    path: '/pages/appointment/rail-ticket-page'
  },
  unaccompanied_minor: {
    category: 'other',
    page: 'unaccompanied-minor-page',
    path: '/pages/appointment/unaccompanied-minor-page'
  },
  medical_consultation: {
    category: 'other',
    page: 'medical-consultation-page',
    path: '/pages/appointment/medical-consultation-page'
  },
  special_needs: {
    category: 'other',
    page: 'special-needs-page',
    path: '/pages/appointment/special-needs-page'
  },
  pet_transportation: {
    category: 'other',
    page: 'pet-transportation-page',
    path: '/pages/appointment/pet-transportation-page'
  },
  air_logistics: {
    category: 'other',
    page: 'air-logistics-page',
    path: '/pages/appointment/air-logistics-page'
  },
  sea_freight: {
    category: 'other',
    page: 'sea-freight-page',
    path: '/pages/appointment/sea-freight-page'
  },
  guide_translation: {
    category: 'guide_translation',
    page: 'guide-translation-page',
    path: '/pages/appointment/guide-translation-page'
  },
  travel_planning: {
    category: 'guide_consulting',
    page: 'travel-planning-page',
    path: '/pages/appointment/travel-planning-page'
  },
  visa_consultation: {
    category: 'consulting',
    page: 'visa-consultation-page',
    path: '/pages/appointment/visa-consultation-page'
  },
  exhibition_service: {
    category: 'consulting',
    page: 'exhibition-service-page',
    path: '/pages/appointment/exhibition-service-page'
  },
  insurance_consultation: {
    category: 'consulting',
    page: 'insurance-consultation-page',
    path: '/pages/appointment/insurance-consultation-page'
  }
};

/**
 * Gets the form page path for a given service type
 */
function getFormPageByServiceType(serviceType) {
  if (!serviceType || typeof serviceType !== 'string') {
    return null;
  }
  
  const config = SERVICE_TYPE_MAP[serviceType];
  return config ? config.path : null;
}

/**
 * Gets the service configuration for a given service type
 */
function getServiceConfig(serviceType) {
  if (!serviceType || typeof serviceType !== 'string') {
    return null;
  }
  
  return SERVICE_TYPE_MAP[serviceType] || null;
}

/**
 * Checks if a service type is valid
 */
function isValidServiceType(serviceType) {
  return serviceType && typeof serviceType === 'string' && SERVICE_TYPE_MAP.hasOwnProperty(serviceType);
}

/**
 * Gets all service types for a given category
 */
function getServiceTypesByCategory(category) {
  if (!category || typeof category !== 'string') {
    return [];
  }
  
  return Object.entries(SERVICE_TYPE_MAP)
    .filter(([_, config]) => config.category === category)
    .map(([serviceType, _]) => serviceType);
}

// All valid service types
const ALL_SERVICE_TYPES = Object.keys(SERVICE_TYPE_MAP);

// All valid categories
const ALL_CATEGORIES = ['travel', 'accommodation', 'other', 'guide_translation', 'guide_consulting', 'consulting'];

describe('Service Routing Property Tests', () => {
  /**
   * Feature: service-appointment-forms, Property 7: Service Type Routing
   * For any service selection, the system SHALL navigate to the correct 
   * form page based on the service type mapping.
   * **Validates: Requirements 17.1**
   */
  describe('Property 7: Service Type Routing', () => {
    test('Every valid service type should map to a valid page path', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          (serviceType) => {
            const pagePath = getFormPageByServiceType(serviceType);
            
            // Should return a non-null path
            expect(pagePath).not.toBeNull();
            
            // Path should start with /pages/appointment/
            expect(pagePath).toMatch(/^\/pages\/appointment\//);
            
            // Path should end with -page
            expect(pagePath).toMatch(/-page$/);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Unknown service types should return null', () => {
      fc.assert(
        fc.property(
          // Filter out JavaScript reserved property names that could cause issues
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => 
            !ALL_SERVICE_TYPES.includes(s) && 
            !['constructor', 'prototype', '__proto__', 'hasOwnProperty', 'toString', 'valueOf'].includes(s)
          ),
          (unknownType) => {
            const pagePath = getFormPageByServiceType(unknownType);
            expect(pagePath).toBeNull();
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Null and undefined service types should return null', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(null, undefined, '', 0, false, [], {}),
          (invalidType) => {
            const pagePath = getFormPageByServiceType(invalidType);
            expect(pagePath).toBeNull();
          }
        ),
        { numRuns: 10 }
      );
    });

    test('Service type to page mapping should be consistent (deterministic)', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          fc.integer({ min: 1, max: 10 }),
          (serviceType, iterations) => {
            // Call the function multiple times
            const results = [];
            for (let i = 0; i < iterations; i++) {
              results.push(getFormPageByServiceType(serviceType));
            }
            
            // All results should be identical
            const firstResult = results[0];
            expect(results.every(r => r === firstResult)).toBe(true);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Every service type should have a valid category', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          (serviceType) => {
            const config = getServiceConfig(serviceType);
            
            expect(config).not.toBeNull();
            expect(config.category).toBeDefined();
            expect(ALL_CATEGORIES).toContain(config.category);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('isValidServiceType should return true for all known service types', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          (serviceType) => {
            expect(isValidServiceType(serviceType)).toBe(true);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('isValidServiceType should return false for unknown service types', () => {
      fc.assert(
        fc.property(
          // Filter out JavaScript reserved property names that could cause issues
          fc.string({ minLength: 1, maxLength: 50 }).filter(s => 
            !ALL_SERVICE_TYPES.includes(s) && 
            !['constructor', 'prototype', '__proto__', 'hasOwnProperty', 'toString', 'valueOf'].includes(s)
          ),
          (unknownType) => {
            expect(isValidServiceType(unknownType)).toBe(false);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Page path should contain the page name from config', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          (serviceType) => {
            const config = getServiceConfig(serviceType);
            const pagePath = getFormPageByServiceType(serviceType);
            
            // The path should contain the page name
            expect(pagePath).toContain(config.page);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('getServiceTypesByCategory should return only service types of that category', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_CATEGORIES),
          (category) => {
            const serviceTypes = getServiceTypesByCategory(category);
            
            // All returned service types should belong to the specified category
            for (const serviceType of serviceTypes) {
              const config = getServiceConfig(serviceType);
              expect(config.category).toBe(category);
            }
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Every service type should be in exactly one category', () => {
      fc.assert(
        fc.property(
          fc.constantFrom(...ALL_SERVICE_TYPES),
          (serviceType) => {
            let categoryCount = 0;
            
            for (const category of ALL_CATEGORIES) {
              const typesInCategory = getServiceTypesByCategory(category);
              if (typesInCategory.includes(serviceType)) {
                categoryCount++;
              }
            }
            
            expect(categoryCount).toBe(1);
          }
        ),
        { numRuns: 100 }
      );
    });

    test('Service type mapping should cover all 16 service types', () => {
      // This is a simple assertion test, not property-based
      expect(ALL_SERVICE_TYPES.length).toBe(16);
      
      // Verify specific service types exist
      const expectedTypes = [
        'airfare', 'hotel', 'vip_lounge', 'airport_transfer', 'rail_ticket',
        'unaccompanied_minor', 'medical_consultation', 'special_needs',
        'pet_transportation', 'air_logistics', 'sea_freight', 'guide_translation',
        'travel_planning', 'visa_consultation', 'exhibition_service', 'insurance_consultation'
      ];
      
      for (const type of expectedTypes) {
        expect(ALL_SERVICE_TYPES).toContain(type);
      }
    });
  });
});
