import { describe, it, expect } from 'vitest';
import { getWebsiteRouteContracts, ScenarioRole } from '../../shared/website/RouteContractSpec';
import { WebsiteRouteManager } from '../../shared/website/WebsiteRouteManager';
import { RouteScenarioMatrix } from '../../shared/website/RouteScenarioMatrix';

describe('RouteContractSpec', () => {
  const contracts = getWebsiteRouteContracts();
  const manager = new WebsiteRouteManager();
  const inventory = manager.getWebsiteRouteInventory();

  it('should cover all inventory routes', () => {
    expect(contracts.length).toBe(inventory.length);
    
    const inventoryPaths = inventory.map(def => 
      manager.resolvePathTemplate(def.pathTemplate, def.params)
    );
    const contractPaths = contracts.map(c => c.path);
    
    // Ensure every path in inventory has a corresponding contract
    inventoryPaths.forEach(path => {
      expect(contractPaths).toContain(path);
    });
  });

  it('should have expectedStatus set for every contract', () => {
    contracts.forEach(contract => {
      expect(contract.expectedStatus).toBeDefined();
      expect(['ok', 'redirect', 'forbidden', 'notFoundAllowed', 'errorRoute']).toContain(contract.expectedStatus);
    });
  });

  it('should have required scenarios based on access level', () => {
    contracts.forEach(contract => {
      const scenarios = Object.keys(contract.scenarios) as ScenarioRole[];
      
      // All routes must have unauth, auth, admin, sponsor scenarios
      expect(scenarios).toContain('unauth');
      expect(scenarios).toContain('auth');
      expect(scenarios).toContain('admin');
      expect(scenarios).toContain('sponsor');

      // Admin and Sponsor routes must also have wrong-role scenario
      if (contract.accessLevel === 'admin' || contract.accessLevel === 'sponsor') {
        expect(scenarios).toContain('wrong-role');
      }
    });
  });

  it('should have correct scenario expectations for admin routes', () => {
    const adminContracts = contracts.filter(c => c.accessLevel === 'admin');
    adminContracts.forEach(contract => {
      expect(contract.scenarios.unauth?.expectedStatus).toBe('redirect');
      expect(contract.scenarios.auth?.expectedStatus).toBe('redirect');
      expect(contract.scenarios.admin?.expectedStatus).toBe('ok');
      expect(contract.scenarios.sponsor?.expectedStatus).toBe('redirect');
      expect(contract.scenarios['wrong-role']?.expectedStatus).toBe('redirect');
    });
  });

  it('should have correct scenario expectations for sponsor routes', () => {
    const sponsorContracts = contracts.filter(c => c.accessLevel === 'sponsor');
    sponsorContracts.forEach(contract => {
      expect(contract.scenarios.unauth?.expectedStatus).toBe('redirect');
      expect(contract.scenarios.auth?.expectedStatus).toBe('redirect');
      expect(contract.scenarios.admin?.expectedStatus).toBe('redirect');
      expect(contract.scenarios.sponsor?.expectedStatus).toBe('ok');
      expect(contract.scenarios['wrong-role']?.expectedStatus).toBe('redirect');
    });
  });

  it('should have expectedRedirectTo set for protected routes (unauth scenario)', () => {
    const protectedContracts = contracts.filter(c => c.accessLevel !== 'public');
    
    // Filter out routes that might have overrides to not be 'redirect'
    const redirectingContracts = protectedContracts.filter(c => c.expectedStatus === 'redirect');
    
    expect(redirectingContracts.length).toBeGreaterThan(0);
    
    redirectingContracts.forEach(contract => {
      expect(contract.expectedRedirectTo).toBeDefined();
      expect(contract.expectedRedirectTo).toMatch(/^\//);
    });
  });

  it('should include default SSR sanity markers', () => {
    contracts.forEach(contract => {
      expect(contract.ssrMustContain).toContain('<!DOCTYPE html>');
      expect(contract.ssrMustContain).toContain('<body');
      expect(contract.ssrMustNotContain).toContain('__NEXT_ERROR__');
      expect(contract.ssrMustNotContain).toContain('Application error: a client-side exception has occurred');
    });
  });

  describe('RouteScenarioMatrix', () => {
    it('should match the number of contracts', () => {
      expect(RouteScenarioMatrix.length).toBe(contracts.length);
    });

    it('should correctly identify routes with param edge cases', () => {
      const edgeCaseRoutes = RouteScenarioMatrix.filter(m => m.hasParamEdgeCases);
      // Based on WebsiteRouteManager.getParamEdgeCases(), we expect at least /races/[id] and /leagues/[id]
      expect(edgeCaseRoutes.length).toBeGreaterThanOrEqual(2);
      
      const paths = edgeCaseRoutes.map(m => m.path);
      expect(paths.some(p => p.startsWith('/races/'))).toBe(true);
      expect(paths.some(p => p.startsWith('/leagues/'))).toBe(true);
    });
  });
});
