/**
 * Utility functions for the AEM Asset Upload Sample
 */

const chalk = require('chalk');
const ora = require('ora');

/**
 * Formats bytes to human-readable format
 * @param {number} bytes - Number of bytes
 * @returns {string} Formatted size string
 */
function formatBytes(bytes) {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

/**
 * Formats time duration in milliseconds to human-readable format
 * @param {number} ms - Duration in milliseconds
 * @returns {string} Formatted time string
 */
function formatTime(ms) {
  if (ms < 1000) return `${ms}ms`;
  const seconds = (ms / 1000).toFixed(2);
  if (seconds < 60) return `${seconds}s`;
  const minutes = Math.floor(seconds / 60);
  const remainingSeconds = (seconds % 60).toFixed(0);
  return `${minutes}m ${remainingSeconds}s`;
}

/**
 * Logs success message
 * @param {string} message - Success message
 */
function logSuccess(message) {
  console.log(chalk.green('✓'), message);
}

/**
 * Logs error message
 * @param {string} message - Error message
 */
function logError(message) {
  console.error(chalk.red('✗'), message);
}

/**
 * Logs info message
 * @param {string} message - Info message
 */
function logInfo(message) {
  console.log(chalk.blue('ℹ'), message);
}

/**
 * Logs warning message
 * @param {string} message - Warning message
 */
function logWarning(message) {
  console.log(chalk.yellow('⚠'), message);
}

/**
 * Creates a progress spinner
 * @param {string} text - Spinner text
 * @returns {object} Ora spinner instance
 */
function createSpinner(text) {
  return ora(text).start();
}

/**
 * Handles upload progress
 * @param {object} uploadInstance - Upload instance from aem-upload (FileSystemUpload or DirectBinaryUpload)
 */
function handleUploadProgress(uploadInstance) {
  uploadInstance.on('foldercreated', (data) => {
    logSuccess(`Created folder: ${chalk.cyan(data.folderName)} at ${chalk.gray(data.targetFolder)}`);
  });

  uploadInstance.on('filestart', (data) => {
    logInfo(`Starting upload: ${chalk.cyan(data.fileName)}`);
  });

  uploadInstance.on('fileprogress', (data) => {
    const percentage = ((data.transferred / data.fileSize) * 100).toFixed(1);
    process.stdout.write(
      `\r  Progress: ${chalk.yellow(percentage + '%')} - ${formatBytes(data.transferred)}/${formatBytes(data.fileSize)}`
    );
  });

  uploadInstance.on('fileend', (data) => {
    process.stdout.write('\n');
    logSuccess(`Completed: ${chalk.cyan(data.fileName)} (${formatTime(data.elapsedTime)})`);
  });

  uploadInstance.on('fileerror', (data) => {
    // Note: fileerror events can be fired during retries, not necessarily final failures
    // Only show these in DEBUG mode to avoid confusion
    if (process.env.DEBUG === 'true') {
      process.stdout.write('\n');
      console.log('🐛 Debug: fileerror event (may be retried):');
      console.log('  fileName:', data.fileName);
      console.log('  error:', data.error);
      console.log('  All keys:', Object.keys(data).join(', '));
      
      // Handle various error structures
      let errorMsg = 'Unknown error';
      if (data.error) {
        if (typeof data.error === 'string') {
          errorMsg = data.error;
        } else if (data.error.message) {
          errorMsg = data.error.message;
        } else if (data.error.code) {
          errorMsg = `Error code: ${data.error.code}`;
        } else {
          try {
            errorMsg = JSON.stringify(data.error);
          } catch (e) {
            errorMsg = String(data.error);
          }
        }
      } else if (data.message) {
        errorMsg = data.message;
      }
      
      logWarning(`  Error (may retry): ${chalk.cyan(data.fileName)} - ${errorMsg}`);
    }
    // In normal mode, don't show fileerror events - they're often just retries
    // Final errors will be shown in the upload summary
  });
}

/**
 * Constructs a clickable AEM Assets UI URL for a given path
 * @param {string} aemUrl - Base AEM URL (e.g., https://author-p12345-e67890.adobeaemcloud.com)
 * @param {string} assetPath - Full asset path in AEM (e.g., /content/dam/my-folder/file.jpg)
 * @returns {string} Full AEM Assets UI URL
 */
function getAemAssetsUrl(aemUrl, assetPath) {
  return `${aemUrl}/ui#/aem/assets.html${assetPath}?appId=aemshell`;
}

/**
 * Displays upload summary
 * @param {object} uploadResult - Upload result object from aem-upload (contains detailedResult and errors)
 * @param {number} totalTime - Total time taken in milliseconds
 */
function displayUploadSummary(uploadResult, totalTime) {
  console.log('\n' + chalk.bold('Upload Summary:'));
  console.log(chalk.gray('─'.repeat(50)));
  
  // Extract detailed results and errors from the upload result
  const detailedResults = uploadResult.detailedResult || [];
  const errors = uploadResult.errors || [];
  
  // Count successful and failed uploads
  // detailedResult items may have a nested 'result' property or be flat
  const totalFiles = detailedResults.length;
  const successfulCount = detailedResults.filter(r => {
    const fileInfo = r.result || r;
    return !fileInfo.error;
  }).length;
  const failedCount = detailedResults.filter(r => {
    const fileInfo = r.result || r;
    return fileInfo.error;
  }).length;
  
  console.log(`Total files: ${chalk.cyan(totalFiles)}`);
  console.log(`Successful: ${chalk.green(successfulCount)}`);
  if (failedCount > 0 || errors.length > 0) {
    console.log(`Failed: ${chalk.red(Math.max(failedCount, errors.length))}`);
  }
  console.log(`Total time: ${chalk.yellow(formatTime(totalTime))}`);
  
  // Calculate total size uploaded (only successful uploads)
  const totalSize = detailedResults
    .filter(r => {
      const fileInfo = r.result || r;
      return !fileInfo.error;
    })
    .reduce((sum, r) => {
      const fileInfo = r.result || r;
      return sum + (fileInfo.fileSize || 0);
    }, 0);
  console.log(`Total size uploaded: ${chalk.cyan(formatBytes(totalSize))}`);
  
  console.log(chalk.gray('─'.repeat(50)));
}

module.exports = {
  formatBytes,
  formatTime,
  logSuccess,
  logError,
  logInfo,
  logWarning,
  createSpinner,
  handleUploadProgress,
  displayUploadSummary,
  getAemAssetsUrl
};

