// src/tests/setup/integration-global-setup.ts
import { execSync } from 'child_process';
import type { Server } from 'http';
import app from '../../../server'; // Import the Express app
import { logger } from '../../services/logger.server';
import { getPool } from '../../services/db/connection.db';

// --- Centralized State for Integration Test Lifecycle ---
let server: Server;
// This will hold the single database pool instance for the entire test run.
let globalPool: ReturnType<typeof getPool> | null = null;

export async function setup() {
  // Ensure we are in the correct environment for these tests.
  process.env.NODE_ENV = 'test';
  console.log(`\n--- [PID:${process.pid}] Running Integration Test GLOBAL Setup ---`);

  // The integration setup is now the single source of truth for preparing the test DB.
  // It runs the same seed script that `npm run db:reset:test` used.
  try {
    console.log(`\n[PID:${process.pid}] Running database seed script...`);
    execSync('npm run db:reset:test', { stdio: 'inherit' });
    console.log(`✅ [PID:${process.pid}] Database seed script finished.`);
  } catch (error) {
    console.error('🔴 Failed to reset and seed the test database. Aborting tests.', error);
    process.exit(1);
  }

  // Initialize the global pool instance once.
  console.log(`[PID:${process.pid}] Initializing global database pool...`);
  globalPool = getPool();

  // Programmatically start the server within the same process.
  const port = process.env.PORT || 3001;
  await new Promise<void>((resolve) => {
    server = app.listen(port, () => {
      console.log(`✅ In-process test server started on port ${port}`);
      resolve();
    });
  });

  /**
   * A local ping function that respects the VITE_API_BASE_URL from the test environment.
   * This is necessary because the global apiClient's URL is configured for browser use.
   */
  const pingTestBackend = async (): Promise<boolean> => {
    const apiUrl = process.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
    try {
        const response = await fetch(`${apiUrl.replace('/api', '')}/api/health/ping`);
        if (!response.ok) return false;
        const text = await response.text();
        return text === 'pong';
    } catch (e) {
        logger.debug({ error: e }, 'Ping failed while waiting for server, this is expected.');
        return false;
    }
  };

  const maxRetries = 15;
  const retryDelay = 1000; 
  for (let i = 0; i < maxRetries; i++) {
    if (await pingTestBackend()) {
      console.log('✅ Backend server is running and responsive.');
      return; 
    }
    console.log(`[PID:${process.pid}] Waiting for backend server... (attempt ${i + 1}/${maxRetries})`);
    await new Promise(resolve => setTimeout(resolve, retryDelay));
  }

  throw new Error('Backend server failed to start.');
}

export async function teardown() {
  console.log(`\n--- [PID:${process.pid}] Running Integration Test GLOBAL Teardown ---`);
  // 1. Stop the server to release any resources it's holding.
  if (server) {
    await new Promise<void>(resolve => server.close(() => resolve()));
    console.log('✅ In-process test server stopped.');
  }
  // 2. Close the single, shared database pool.
  if (globalPool) {
    await globalPool.end();
    console.log('✅ Global database pool teardown complete.');
  }
}