/**
 * Setup Verification Script
 * 
 * Run this script to verify your environment is configured correctly
 * before attempting to upload assets.
 */

const fs = require('fs');
const path = require('path');
const https = require('https');
const http = require('http');

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

function log(message, color = 'reset') {
  console.log(colors[color] + message + colors.reset);
}

function logSuccess(message) {
  log('✓ ' + message, 'green');
}

function logError(message) {
  log('✗ ' + message, 'red');
}

function logWarning(message) {
  log('⚠ ' + message, 'yellow');
}

function logInfo(message) {
  log('ℹ ' + message, 'blue');
}

/**
 * Check if .env file exists and is configured
 */
function checkEnvFile() {
  log('\n1. Checking .env file...', 'bold');
  
  const envPath = path.join(__dirname, '.env');
  
  if (!fs.existsSync(envPath)) {
    logError('.env file not found');
    logInfo('Run: cp env.example .env');
    return false;
  }
  
  logSuccess('.env file exists');
  
  // Load .env
  require('dotenv').config();
  
  // Check required variables
  const checks = [
    { key: 'AEM_URL', required: true },
    { key: 'AEM_USERNAME', required: false },
    { key: 'AEM_PASSWORD', required: false },
    { key: 'AEM_BEARER_TOKEN', required: false },
    { key: 'AEM_SERVICE_CREDENTIALS_FILE', required: false },
    { key: 'TARGET_FOLDER', required: true }
  ];
  
  let allGood = true;
  
  for (const check of checks) {
    const value = process.env[check.key];
    if (!value || value.trim() === '') {
      if (check.required) {
        logError(`${check.key} is not set`);
        allGood = false;
      }
    } else {
      logSuccess(`${check.key} is configured`);
    }
  }
  
  // Check authentication
  const hasBasicAuth = process.env.AEM_USERNAME && process.env.AEM_PASSWORD;
  const hasBearerToken = process.env.AEM_BEARER_TOKEN;
  const hasServiceCredsPath = process.env.AEM_SERVICE_CREDENTIALS_FILE;
  
  // Validate service credentials file if path is provided
  let hasValidServiceCreds = false;
  if (hasServiceCredsPath) {
    const serviceCredsPath = path.isAbsolute(hasServiceCredsPath) 
      ? hasServiceCredsPath 
      : path.join(__dirname, hasServiceCredsPath);
    
    if (fs.existsSync(serviceCredsPath)) {
      try {
        const fileContent = fs.readFileSync(serviceCredsPath, 'utf8');
        const credentials = JSON.parse(fileContent);
        
        // Basic validation of service credentials structure
        if (credentials.integration && 
            credentials.integration.technicalAccount && 
            credentials.integration.privateKey) {
          logSuccess('Service credentials configured and valid');
          hasValidServiceCreds = true;
        } else {
          logError('Service credentials file is missing required fields');
          logInfo('Ensure the file was downloaded from AEM Developer Console');
          allGood = false;
        }
      } catch (error) {
        logError(`Service credentials file is invalid: ${error.message}`);
        logInfo('Ensure the file contains valid JSON from AEM Developer Console');
        allGood = false;
      }
    } else {
      logError(`Service credentials file not found: ${serviceCredsPath}`);
      logInfo('Check the path in AEM_SERVICE_CREDENTIALS_FILE');
      allGood = false;
    }
  }
  
  // Check if at least one authentication method is configured
  if (!hasBasicAuth && !hasBearerToken && !hasValidServiceCreds) {
    logError('No valid authentication configured');
    logInfo('Set one of:');
    logInfo('  - AEM_SERVICE_CREDENTIALS_FILE (recommended for production)');
    logInfo('  - AEM_BEARER_TOKEN (for testing)');
    logInfo('  - AEM_USERNAME/AEM_PASSWORD (for development)');
    allGood = false;
  } else {
    if (hasBasicAuth) {
      logSuccess('Basic authentication configured');
    }
    if (hasBearerToken) {
      logSuccess('Bearer token configured');
    }
  }
  
  return allGood;
}

/**
 * Check Node.js version
 */
function checkNodeVersion() {
  log('\n2. Checking Node.js version...', 'bold');
  
  const version = process.version;
  const majorVersion = parseInt(version.split('.')[0].substring(1));
  
  if (majorVersion >= 18) {
    logSuccess(`Node.js ${version} (compatible)`);
    return true;
  } else {
    logError(`Node.js ${version} (requires v18 or higher)`);
    return false;
  }
}

/**
 * Check if dependencies are installed
 */
function checkDependencies() {
  log('\n3. Checking dependencies...', 'bold');
  
  const packageJson = require('./package.json');
  const dependencies = Object.keys(packageJson.dependencies);
  
  let allInstalled = true;
  
  for (const dep of dependencies) {
    try {
      require.resolve(dep);
      logSuccess(`${dep} is installed`);
    } catch (e) {
      logError(`${dep} is NOT installed`);
      allInstalled = false;
    }
  }
  
  if (!allInstalled) {
    logInfo('Run: npm install');
  }
  
  return allInstalled;
}

/**
 * Check sample assets
 */
function checkSampleAssets() {
  log('\n4. Checking sample assets...', 'bold');
  
  const assetsDir = path.join(__dirname, 'sample-assets');
  
  if (!fs.existsSync(assetsDir)) {
    logError('sample-assets directory not found');
    return false;
  }
  
  // Recursively count all files in the directory
  function countFilesRecursively(dir) {
    let count = 0;
    const items = [];
    
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    for (const entry of entries) {
      if (entry.name.startsWith('.') || entry.name === 'README.md') continue;
      
      const fullPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        const subResult = countFilesRecursively(fullPath);
        count += subResult.count;
        items.push(...subResult.items);
      } else if (entry.isFile()) {
        count++;
        const stats = fs.statSync(fullPath);
        const relativePath = path.relative(assetsDir, fullPath);
        items.push({ path: relativePath, size: stats.size });
      }
    }
    
    return { count, items };
  }
  
  const result = countFilesRecursively(assetsDir);
  
  if (result.count === 0) {
    logWarning('No files found in sample-assets directory');
    logInfo('Add some files to sample-assets/ to test uploads');
    return true; // Not critical
  }
  
  logSuccess(`Found ${result.count} file(s) in sample-assets/`);
  result.items.slice(0, 10).forEach(item => {
    const sizeKB = (item.size / 1024).toFixed(2);
    log(`  → ${item.path} (${sizeKB} KB)`);
  });
  
  if (result.count > 10) {
    log(`  ... and ${result.count - 10} more file(s)`);
  }
  
  return true;
}

/**
 * Test AEM connectivity
 */
async function testAEMConnection() {
  log('\n5. Testing AEM connectivity...', 'bold');
  
  if (!process.env.AEM_URL) {
    logError('AEM_URL not configured, skipping connectivity test');
    return false;
  }
  
  const url = process.env.AEM_URL;
  logInfo(`Testing connection to: ${url}`);
  
  return new Promise((resolve) => {
    try {
      const parsedUrl = new URL(url);
      const protocol = parsedUrl.protocol === 'https:' ? https : http;
      
      const options = {
        hostname: parsedUrl.hostname,
        port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
        path: '/libs/granite/core/content/login.html',
        method: 'HEAD',
        timeout: 10000
      };
      
      const req = protocol.request(options, (res) => {
        if (res.statusCode === 200 || res.statusCode === 302 || res.statusCode === 401) {
          logSuccess(`AEM is reachable (HTTP ${res.statusCode})`);
          if (res.statusCode === 401) {
            logInfo('Received 401 - This is normal, authentication will be handled during upload');
          }
          resolve(true);
        } else {
          logWarning(`AEM responded with HTTP ${res.statusCode}`);
          resolve(true); // Still reachable
        }
      });
      
      req.on('error', (error) => {
        logError(`Cannot reach AEM: ${error.message}`);
        logInfo('Check your AEM_URL and network connection');
        resolve(false);
      });
      
      req.on('timeout', () => {
        logError('Connection timeout');
        logInfo('AEM might be slow or unreachable');
        req.destroy();
        resolve(false);
      });
      
      req.end();
      
    } catch (error) {
      logError(`Invalid AEM_URL: ${error.message}`);
      resolve(false);
    }
  });
}

/**
 * Main verification function
 */
async function main() {
  log('\n╔════════════════════════════════════════════════════════╗', 'blue');
  log('║     AEM Asset Upload - Setup Verification             ║', 'blue');
  log('╚════════════════════════════════════════════════════════╝\n', 'blue');
  
  const results = [];
  
  // Run all checks
  results.push(await checkNodeVersion());
  results.push(await checkDependencies());
  results.push(await checkEnvFile());
  results.push(await checkSampleAssets());
  results.push(await testAEMConnection());
  
  // Summary
  log('\n' + '═'.repeat(60), 'blue');
  log('VERIFICATION SUMMARY', 'bold');
  log('═'.repeat(60), 'blue');
  
  const passed = results.filter(r => r === true).length;
  const total = results.length;
  
  if (passed === total) {
    log(`\n✓ All checks passed (${passed}/${total})`, 'green');
    log('\nYou\'re ready to upload assets!', 'green');
    log('Run: npm start\n', 'blue');
  } else {
    log(`\n⚠ ${passed}/${total} checks passed`, 'yellow');
    log('\nPlease fix the issues above before proceeding.\n', 'yellow');
  }
}

// Run verification
main().catch(error => {
  logError(`\nVerification failed: ${error.message}`);
  process.exit(1);
});

