import { execSync } from 'child_process';

import { PrismaClient } from '@prisma/client';

// Test database configuration
export const TEST_DATABASE_URL = process.env.TEST_DATABASE_URL || 'postgresql://test:test@localhost:5433/test_iam_db';
export const TEST_REDIS_URL = process.env.TEST_REDIS_URL || 'redis://localhost:6380';

// Global test database client
let prisma: PrismaClient;

/**
 * Setup test database before all tests
 */
export async function setupTestDatabase() {
  try {
    console.warn('🚀 Setting up test database...');

    // Create test database if it doesn't exist
    try {
      execSync(`createdb -U test -h localhost -p 5433 test_iam_db`, {
        stdio: 'pipe',
        env: { ...process.env, PGPASSWORD: 'test' }
      });
      console.warn('✅ Test database created');
    } catch {
      // Database might already exist, continue
      console.warn('ℹ️  Test database already exists');
    }

    // Initialize Prisma client with test database
    // Set DATABASE_URL for test database
    process.env.DATABASE_URL = TEST_DATABASE_URL;
    prisma = new PrismaClient();

    // Connect to database
    await prisma.$connect();
    console.warn('✅ Connected to test database');

    // Run migrations
    console.warn('📦 Running database migrations...');
    execSync('cd services/iam-service && pnpm prisma:migrate:deploy', {
      stdio: 'inherit',
      env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL }
    });
    console.warn('✅ Migrations completed');

    // Seed test data
    console.warn('🌱 Seeding test data...');
    execSync('cd services/iam-service && pnpm prisma:db:seed', {
      stdio: 'inherit',
      env: { ...process.env, DATABASE_URL: TEST_DATABASE_URL }
    });
    console.warn('✅ Test data seeded');

    return prisma;
  } catch (error) {
    console.error('❌ Failed to setup test database:', error);
    throw error;
  }
}

/**
 * Clean up test database after all tests
 */
export async function teardownTestDatabase() {
  try {
    console.warn('🧹 Cleaning up test database...');

    if (prisma) {
      // Clear all data
      await prisma.$transaction([
        prisma.userPermission.deleteMany(),
        prisma.userRole.deleteMany(),
        prisma.refreshToken.deleteMany(),
        prisma.session.deleteMany(),
        prisma.mFADevice.deleteMany(),
        prisma.authEvent.deleteMany(),
        prisma.user.deleteMany(),
        prisma.role.deleteMany(),
        prisma.permission.deleteMany(),
        prisma.organization.deleteMany(),
        prisma.group.deleteMany(),
        prisma.groupMember.deleteMany(),
        prisma.userProfile.deleteMany(),
        prisma.identityVerification.deleteMany(),
        prisma.accessRequest.deleteMany(),
        prisma.accessReview.deleteMany(),
        prisma.complianceReport.deleteMany(),
        prisma.policy.deleteMany(),
        prisma.riskScore.deleteMany(),
        prisma.feature.deleteMany(),
      ]);

      await prisma.$disconnect();
      console.warn('✅ Test database cleaned and disconnected');
    }
  } catch (error) {
    console.error('❌ Failed to cleanup test database:', error);
    throw error;
  }
}

/**
 * Get test database client
 */
export function getTestPrisma(): PrismaClient {
  if (!prisma) {
    throw new Error('Test database not initialized. Call setupTestDatabase() first.');
  }
  return prisma;
}

/**
 * Test utilities for creating test data
 */
export const testUtils = {
  /**
   * Create a test user
   */
  async createTestUser(overrides: Partial<any> = {}) {
    const prisma = getTestPrisma();
    const defaultUser = {
      email: `test-${Date.now()}@example.com`,
      username: `testuser-${Date.now()}`,
      passwordHash: '$2b$12$hashedpassword',
      isActive: true,
      emailVerified: true,
      mfaEnabled: false,
      failedLoginAttempts: 0,
      lockedUntil: null,
      createdAt: new Date(),
      updatedAt: new Date(),
      ...overrides,
    };

    return await prisma.user.create({ data: defaultUser });
  },

  /**
   * Create a test role
   */
  async createTestRole(overrides: Partial<any> = {}) {
    const prisma = getTestPrisma();
    const defaultRole = {
      name: `test-role-${Date.now()}`,
      displayName: 'User', // Added displayName
      description: 'Test role for integration tests',
      createdAt: new Date(),
      updatedAt: new Date(),
      ...overrides,
    };

    return await prisma.role.create({ data: defaultRole });
  },

  /**
   * Create a test permission
   */
  async createTestPermission(overrides: Partial<any> = {}) {
    const prisma = getTestPrisma();
    const defaultPermission = {
      resource: 'test-resource',
      action: 'test-action',
      scope: 'test-scope',
      createdAt: new Date(),
      updatedAt: new Date(),
      ...overrides,
    };

    return await prisma.permission.create({ data: defaultPermission });
  },

  /**
   * Assign role to user
   */
  assignRole: async (userId: string, roleName: string) => {
    const prisma = getTestPrisma();
    const role = await prisma.role.findUnique({ where: { name: roleName } });
    if (role) {
      return await prisma.userRole.create({ // Renamed prisma.userRoles to prisma.userRole
        data: {
          userId,
          roleId: role.id,
        },
      });
    }
    return null;
  },

  /**
   * Grant permission to user
   */
  grantPermission: async (userId: string, resource: string, action: string, scope: string = 'own') => {
    const prisma = getTestPrisma();
    const permission = await prisma.permission.create({
      data: {
        resource,
        action,
        scope,
      },
    });

    return await prisma.userPermission.create({ // Renamed prisma.userPermissions to prisma.userPermission
      data: {
        userId,
        permissionId: permission.id,
      },
    });
  },
};