import { execSync } from 'child_process';
import * as path from 'path';
import * as dotenv from 'dotenv';

// Load test environment
dotenv.config({ path: path.resolve(__dirname, '../../.env.test') });

export default async function globalSetup() {
  console.log('\n🚀 Starting E2E test environment setup...');

  try {
    const useDocker = process.env.USE_DOCKER !== 'false';

    if (useDocker) {
      // Try to use Docker
      const dockerAvailable = checkDockerAvailable();

      if (dockerAvailable) {
        // Start test database container
        console.log('📦 Starting test database container...');
        execSync('docker-compose -f docker-compose.test.yml up -d', {
          cwd: path.resolve(__dirname, '../..'),
          stdio: 'inherit',
        });
      } else {
        console.log('⚠️  Docker not available. Assuming database is already running...');
        console.log('   Make sure PostgreSQL is running on port 5434');
        console.log('   Or set USE_DOCKER=false and configure DATABASE_URL');
      }
    } else {
      console.log('📌 Docker disabled. Using existing database...');
    }

    // Wait for database to be ready
    console.log('⏳ Waiting for database to be ready...');
    await waitForDatabase();

    // Push Prisma schema to database
    console.log('🔄 Pushing Prisma schema to database...');
    execSync('npx prisma db push --force-reset --accept-data-loss', {
      cwd: path.resolve(__dirname, '../..'),
      stdio: 'inherit',
      env: {
        ...process.env,
        DATABASE_URL: process.env.DATABASE_URL,
      },
    });

    // Generate Prisma client
    console.log('🔧 Generating Prisma client...');
    execSync('npx prisma generate', {
      cwd: path.resolve(__dirname, '../..'),
      stdio: 'inherit',
    });

    console.log('✅ E2E test environment setup complete!\n');
  } catch (error) {
    console.error('❌ Failed to setup E2E test environment:', error);
    throw error;
  }
}

function checkDockerAvailable(): boolean {
  try {
    execSync('docker info', { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

async function waitForDatabase(maxAttempts = 30, delayMs = 1000): Promise<void> {
  const { Client } = await import('pg');

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const client = new Client({
      connectionString: process.env.DATABASE_URL,
    });

    try {
      await client.connect();
      await client.query('SELECT 1');
      await client.end();
      console.log(`   Database ready after ${attempt} attempt(s)`);
      return;
    } catch (error) {
      await client.end().catch(() => {});
      if (attempt === maxAttempts) {
        throw new Error(`Database not ready after ${maxAttempts} attempts. Is PostgreSQL running on port 5434?`);
      }
      if (attempt % 5 === 0) {
        console.log(`   Still waiting for database... (attempt ${attempt}/${maxAttempts})`);
      }
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
  }
}
