/**
 * Website SSR Smoke Tests
 * 
 * Run with: npx vitest run tests/smoke/website-ssr.test.ts --config vitest.smoke.config.ts
 */
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
import { getWebsiteRouteContracts, RouteContract } from '../shared/website/RouteContractSpec';
import { WebsiteServerHarness } from '../integration/harness/WebsiteServerHarness';
import { ApiServerHarness } from '../integration/harness/ApiServerHarness';

const WEBSITE_BASE_URL = process.env.WEBSITE_BASE_URL || 'http://localhost:3000';
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:3001';

describe('Website SSR Contract Suite', () => {
  const contracts = getWebsiteRouteContracts();
  let websiteHarness: WebsiteServerHarness | null = null;
  let apiHarness: ApiServerHarness | null = null;
  let errorCount500 = 0;

  beforeAll(async () => {
    // 1. Ensure API is running
    if (API_BASE_URL.includes('localhost')) {
      try {
        await fetch(`${API_BASE_URL}/health`);
        console.log(`API already running at ${API_BASE_URL}`);
      } catch (e) {
        console.log(`Starting API server harness on ${API_BASE_URL}...`);
        apiHarness = new ApiServerHarness({
          port: parseInt(new URL(API_BASE_URL).port) || 3001,
        });
        await apiHarness.start();
      }
    }

    // 2. Ensure Website is running
    if (WEBSITE_BASE_URL.includes('localhost')) {
      try {
        await fetch(WEBSITE_BASE_URL, { method: 'HEAD' });
        console.log(`Website server already running at ${WEBSITE_BASE_URL}`);
      } catch (e) {
        console.log(`Starting website server harness on ${WEBSITE_BASE_URL}...`);
        websiteHarness = new WebsiteServerHarness({
          port: parseInt(new URL(WEBSITE_BASE_URL).port) || 3000,
        });
        await websiteHarness.start();
      }
    }
  }, 120000);

  afterAll(async () => {
    if (websiteHarness) {
      await websiteHarness.stop();
    }
    if (apiHarness) {
      await apiHarness.stop();
    }

    // Fail suite on bursts of 500s (e.g. > 3)
    if (errorCount500 > 3) {
        throw new Error(`Suite failed due to high error rate: ${errorCount500} routes returned 500`);
    }

    // Fail on uncaught exceptions in logs
    if (websiteHarness?.hasErrorPatterns()) {
        console.error('Server logs contained error patterns:\n' + websiteHarness.getLogTail(50));
        throw new Error('Suite failed due to error patterns in server logs');
    }
  });

  test.each(contracts)('Contract: $path', async (contract: RouteContract) => {
    const url = `${WEBSITE_BASE_URL}${contract.path}`;
    
    let response: Response;
    try {
        response = await fetch(url, { redirect: 'manual' });
    } catch (e) {
        const logTail = websiteHarness ? `\nServer Log Tail:\n${websiteHarness.getLogTail(20)}` : '';
        throw new Error(`Failed to fetch ${url}: ${e.message}${logTail}`);
    }

    const status = response.status;
    const text = await response.text();
    const location = response.headers.get('location');

    if (status === 500 && contract.expectedStatus !== 'errorRoute') {
        errorCount500++;
    }

    const failureContext = `
Route: ${contract.path}
Status: ${status}
Location: ${location || 'N/A'}
HTML (clipped): ${text.slice(0, 500)}...
${websiteHarness ? `\nServer Log Tail:\n${websiteHarness.getLogTail(10)}` : ''}
    `.trim();

    // 1. Status class matches expectedStatus
    if (contract.expectedStatus === 'ok') {
      expect(status, failureContext).toBe(200);
    } else if (contract.expectedStatus === 'redirect') {
      expect(status, failureContext).toBeGreaterThanOrEqual(300);
      expect(status, failureContext).toBeLessThan(400);
    } else if (contract.expectedStatus === 'notFoundAllowed') {
      expect([200, 404], failureContext).toContain(status);
    } else if (contract.expectedStatus === 'errorRoute') {
      expect([200, 404, 500], failureContext).toContain(status);
    }

    // 2. Redirect location semantics
    if (contract.expectedStatus === 'redirect' && contract.expectedRedirectTo) {
      expect(location, failureContext).toContain(contract.expectedRedirectTo);
      if (contract.accessLevel !== 'public' && contract.expectedRedirectTo.includes('/auth/login')) {
          expect(location, failureContext).toContain('returnTo=');
      }
    }

    // 3. HTML sanity checks
    if (status === 200 || (status === 404 && contract.expectedStatus === 'notFoundAllowed')) {
      if (contract.ssrMustContain) {
        for (const pattern of contract.ssrMustContain) {
          expect(text, failureContext).toMatch(pattern);
        }
      }
      if (contract.ssrMustNotContain) {
        for (const pattern of contract.ssrMustNotContain) {
          expect(text, failureContext).not.toMatch(pattern);
        }
      }
      if (contract.minTextLength) {
        expect(text.length, failureContext).toBeGreaterThanOrEqual(contract.minTextLength);
      }
    }
  });
});
