import { spawnSync } from 'child_process';
import * as fs from 'fs';
import * as http from 'http';
import * as path from 'path';

const ROOT_DIR = path.resolve(__dirname, '../../../');
const MAX_STARTUP_TIME = 180000; // 3 minutes

async function waitForUrl(url: string, timeout: number = MAX_STARTUP_TIME): Promise<void> {
  const startTime = Date.now();
  while (Date.now() - startTime < timeout) {
    try {
      const httpUrl = new URL(url);
      const response = await new Promise<http.IncomingMessage>((resolve, reject) => {
        const req = http.get(httpUrl, (res) => {
          resolve(res);
        });
        req.on('error', reject);
        req.setTimeout(5000);
      });
      if (response.statusCode && response.statusCode < 500) {
        console.log(`✓ Service ready at ${url}`);
        return;
      }
    } catch (e) {
      // Service not ready, continue waiting
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
  throw new Error(`Timeout waiting for service at ${url}`);
}

function runComposeCommand(args: string[]): void {
  try {
    // Use docker compose (modern Docker CLI syntax)
    const result = spawnSync('docker', ['compose', ...args], { 
      cwd: ROOT_DIR, 
      stdio: 'inherit',
      shell: false
    });
    if (result.error) {
      throw result.error;
    }
  } catch (e) {
    throw new Error(`Failed to run docker compose: ${(e as Error).message}`);
  }
}

export default async function globalSetup(): Promise<void> {
  console.log('🚀 Starting global test setup...');

  // Load environment
  const envFile = process.env.ENV_FILE || '.env';
  const envPath = path.join(ROOT_DIR, envFile);
  if (fs.existsSync(envPath)) {
    require('dotenv').config({ path: envPath });
  } else {
    console.warn(`⚠ ENV file not found at ${envPath}, using defaults`);
  }

  // Check if we should use real stack or mocks
  const useMocks = process.env.FELLOWSHIP_USE_MOCKS?.toLowerCase() === 'true';
  if (useMocks) {
    console.log('✓ Using mocks for tests (FELLOWSHIP_USE_MOCKS=true)');
    return;
  }

  console.log('🐳 Starting Fellowship SUT stack via docker compose...');
  // Start (or restart) containers without recreating — images are rebuilt only when
  // Dockerfiles/sources change.  Per-test DB state is cleaned up via the
  // /api/shop/test-reset endpoint called in each test's beforeEach hook.
  runComposeCommand(['up', '-d', '--build']);

  console.log('📍 Waiting for services to be ready...');
  await waitForUrl('http://localhost/api/health', MAX_STARTUP_TIME);
  await waitForUrl('http://localhost/login', MAX_STARTUP_TIME);
  await waitForUrl('http://localhost:3000', MAX_STARTUP_TIME);

  console.log('✓ All services are ready!');
}
