/**
 * @ai-summary CLI script for creating initial admin user on fresh deployments
 * @ai-context Runs inside backend container with access to Auth0 and PostgreSQL
 *
 * Usage: node dist/_system/cli/create-admin.js
 *
 * Interactive prompts for email and password, then:
 * 1. Checks if any admin exists (errors if yes)
 * 2. Creates user in Auth0 via Management API
 * 3. Creates user_profile record
 * 4. Creates admin_users record with audit log
 */

import * as readline from 'readline';
import { Pool } from 'pg';
import { appConfig } from '../../core/config/config-loader';
import { auth0ManagementClient } from '../../core/auth/auth0-management.client';
import { UserProfileRepository } from '../../features/user-profile/data/user-profile.repository';
import { AdminRepository } from '../../features/admin/data/admin.repository';
import { AdminService } from '../../features/admin/domain/admin.service';

// Terminal color codes
const colors = {
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  cyan: '\x1b[36m',
  reset: '\x1b[0m',
  bold: '\x1b[1m',
};

function printInfo(msg: string): void {
  console.log(`${colors.green}[INFO]${colors.reset} ${msg}`);
}

function printError(msg: string): void {
  console.log(`${colors.red}[ERROR]${colors.reset} ${msg}`);
}

function printWarn(msg: string): void {
  console.log(`${colors.yellow}[WARN]${colors.reset} ${msg}`);
}

/**
 * Prompt for text input
 */
function prompt(rl: readline.Interface, question: string): Promise<string> {
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      resolve(answer.trim());
    });
  });
}

/**
 * Prompt for password input (masked - characters not echoed)
 */
function promptPassword(question: string): Promise<string> {
  return new Promise((resolve) => {
    process.stdout.write(question);

    const stdin = process.stdin;
    const wasRaw = stdin.isRaw;

    stdin.setRawMode?.(true);
    stdin.resume();

    let password = '';

    const onData = (char: Buffer): void => {
      const c = char.toString();

      if (c === '\n' || c === '\r') {
        stdin.removeListener('data', onData);
        stdin.setRawMode?.(wasRaw);
        stdin.pause();
        console.log(); // newline after password
        resolve(password);
      } else if (c === '\u0003') {
        // Ctrl+C - exit gracefully
        console.log('\n\nAborted by user.');
        process.exit(1);
      } else if (c === '\u007f' || c === '\b') {
        // Backspace
        password = password.slice(0, -1);
        // Optionally show backspace effect
        if (password.length >= 0) {
          process.stdout.write('\b \b');
        }
      } else if (c.charCodeAt(0) >= 32) {
        // Printable character
        password += c;
        process.stdout.write('*'); // Show asterisk for each character
      }
    };

    stdin.on('data', onData);
  });
}

/**
 * Validate email format
 */
function validateEmail(email: string): boolean {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

/**
 * Validate password strength
 * Returns error message or null if valid
 */
function validatePassword(password: string): string | null {
  if (password.length < 8) {
    return 'Password must be at least 8 characters long';
  }
  if (!/[A-Z]/.test(password)) {
    return 'Password must contain at least one uppercase letter';
  }
  if (!/[a-z]/.test(password)) {
    return 'Password must contain at least one lowercase letter';
  }
  if (!/[0-9]/.test(password)) {
    return 'Password must contain at least one number';
  }
  return null;
}

/**
 * Wait for database to be available
 */
async function waitForDatabase(pool: Pool, timeoutMs = 30000): Promise<void> {
  const start = Date.now();
  while (true) {
    try {
      await pool.query('SELECT 1');
      return;
    } catch (error) {
      if (Date.now() - start > timeoutMs) {
        throw new Error('Database connection timeout');
      }
      await new Promise((res) => setTimeout(res, 1000));
    }
  }
}

async function main(): Promise<void> {
  console.log('');
  console.log(`${colors.bold}${colors.cyan}========================================${colors.reset}`);
  console.log(`${colors.bold}${colors.cyan}  MotoVaultPro - Create Admin User${colors.reset}`);
  console.log(`${colors.bold}${colors.cyan}========================================${colors.reset}`);
  console.log('');

  // Initialize database pool
  const pool = new Pool({
    connectionString: appConfig.getDatabaseUrl(),
  });

  try {
    // Wait for database
    printInfo('Connecting to database...');
    await waitForDatabase(pool);
    printInfo('Database connected.');

    // Initialize repositories and services
    const userProfileRepo = new UserProfileRepository(pool);
    const adminRepo = new AdminRepository(pool);
    const adminService = new AdminService(adminRepo);

    // Step 1: Check if any admin already exists
    printInfo('Checking for existing admin users...');
    const existingAdmins = await adminService.getActiveAdmins();

    if (existingAdmins.length > 0) {
      console.log('');
      printError('An admin user already exists!');
      console.log('');
      console.log(`  Found ${existingAdmins.length} existing admin(s):`);
      for (const admin of existingAdmins) {
        console.log(`    - ${admin.email} (${admin.role})`);
      }
      console.log('');
      console.log('  This command is only for initial admin setup on fresh deployments.');
      console.log('  To create additional admins, use the admin panel.');
      console.log('');
      process.exit(1);
    }

    printInfo('No existing admins found. Proceeding with setup.');
    console.log('');

    // Step 2: Create readline interface for interactive prompts
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });

    // Prompt for email
    let email: string;
    while (true) {
      email = await prompt(rl, 'Enter admin email: ');
      if (!email) {
        printError('Email is required');
        continue;
      }
      if (!validateEmail(email)) {
        printError('Please enter a valid email address');
        continue;
      }
      break;
    }

    // Close readline before password prompts (we handle raw input directly)
    rl.close();

    // Prompt for password
    let password: string;
    while (true) {
      password = await promptPassword('Enter password: ');
      const passwordError = validatePassword(password);
      if (passwordError) {
        printError(passwordError);
        continue;
      }

      const confirmPassword = await promptPassword('Confirm password: ');
      if (password !== confirmPassword) {
        printError('Passwords do not match');
        continue;
      }
      break;
    }

    console.log('');
    printInfo('Creating admin user...');

    // Step 3: Create user in Auth0 (with email pre-verified for trusted CLI-created admins)
    printInfo('Creating user in Auth0...');
    let auth0Sub: string;
    try {
      auth0Sub = await auth0ManagementClient.createUser({ email, password, emailVerified: true });
      printInfo(`Auth0 user created: ${auth0Sub}`);
    } catch (error) {
      printError(
        `Failed to create Auth0 user: ${error instanceof Error ? error.message : 'Unknown error'}`
      );
      process.exit(1);
    }

    // Step 4: Create user_profile record (with email verified for trusted CLI-created admins)
    printInfo('Creating user profile...');
    try {
      const displayName = email.split('@')[0]; // Use email prefix as display name
      await userProfileRepo.create(auth0Sub, email, displayName);
      // Mark email as verified in database (trusted admin created via CLI)
      await userProfileRepo.updateEmailVerified(auth0Sub, true);
      printInfo('User profile created (email verified).');
    } catch (error) {
      printError(
        `Failed to create user profile: ${error instanceof Error ? error.message : 'Unknown error'}`
      );
      // Attempt to clean up Auth0 user
      printWarn('Attempting to clean up Auth0 user...');
      try {
        await auth0ManagementClient.deleteUser(auth0Sub);
        printInfo('Auth0 user cleaned up.');
      } catch (cleanupError) {
        printError('Failed to clean up Auth0 user - manual cleanup may be required');
      }
      process.exit(1);
    }

    // Step 5: Create admin_users record
    printInfo('Creating admin record...');
    try {
      const admin = await adminService.createAdmin(
        email,
        'admin',
        auth0Sub,
        'system-cli' // createdBy indicator for CLI-created admins
      );
      printInfo(`Admin record created: ${admin.email} (${admin.role})`);
    } catch (error) {
      printError(
        `Failed to create admin record: ${error instanceof Error ? error.message : 'Unknown error'}`
      );
      printWarn('User was created but admin privileges were not assigned.');
      printWarn('You may need to manually grant admin access via the database.');
      process.exit(1);
    }

    // Success
    console.log('');
    console.log(`${colors.bold}${colors.green}========================================${colors.reset}`);
    console.log(`${colors.bold}${colors.green}  Admin User Created Successfully!${colors.reset}`);
    console.log(`${colors.bold}${colors.green}========================================${colors.reset}`);
    console.log('');
    console.log(`  Email:    ${email}`);
    console.log(`  Role:     admin`);
    console.log(`  Auth0 ID: ${auth0Sub}`);
    console.log('');
    console.log('  You can now log in at https://motovaultpro.com');
    console.log('');
  } catch (error) {
    printError(`Unexpected error: ${error instanceof Error ? error.message : 'Unknown error'}`);
    process.exit(1);
  } finally {
    await pool.end();
  }
}

// Only run if executed directly
if (require.main === module) {
  main();
}
