// Error Logger Utility
// Centralized error logging with rotation and request context tracking

const fsp = require('fs').promises;
const path = require('path');
const { LIMITS } = require('./constants');

const ERROR_LOG_FILE = path.join(__dirname, 'error.log');
const MAX_ERROR_LOG_SIZE = LIMITS.ERROR_LOG_SIZE;

/**
 * Check if file exists
 */
async function exists(filepath) {
  try {
    await fsp.access(filepath);
    return true;
  } catch {
    return false;
  }
}

/**
 * Log error with context and rotation
 * @param {string} context - Where the error occurred
 * @param {Error|string} error - The error to log
 * @param {Object} additionalInfo - Additional context (req, etc.)
 */
async function logError(context, error, additionalInfo = {}) {
  const timestamp = new Date().toISOString();

  // Extract request context if a request object is provided
  const requestContext = extractRequestContext(additionalInfo.req);
  if (additionalInfo.req) {
    delete additionalInfo.req; // Remove req to avoid circular refs
  }

  const logEntry = {
    timestamp,
    context,
    ...requestContext,
    error: {
      message: error.message || error,
      stack: error.stack,
      code: error.code
    },
    ...additionalInfo
  };

  // Format log line with request context
  const contextInfo = Object.keys(requestContext).length > 0
    ? `\nRequest Context: ${JSON.stringify(requestContext, null, 2)}`
    : '';
  const logLine = `[${timestamp}] ${context}: ${error.message || error}\n${error.stack || ''}${contextInfo}\nAdditional Info: ${JSON.stringify(additionalInfo, null, 2)}\n${'='.repeat(80)}\n`;

  try {
    // Rotate log if it exceeds max size
    await rotateLogIfNeeded();
    await fsp.appendFile(ERROR_LOG_FILE, logLine);
  } catch (e) {
    console.error('Failed to write to error log', e.message);
  }
}

/**
 * Extract request context from Express request object
 */
function extractRequestContext(req) {
  if (!req) return {};

  const clientIP = req.ip || req.socket?.remoteAddress || '';
  
  return {
    requestId: req.id,
    ip: clientIP,
    userAgent: req.get('user-agent'),
    method: req.method,
    path: req.path
  };
}

/**
 * Rotate log file if it exceeds max size
 */
async function rotateLogIfNeeded() {
  try {
    const stats = await fsp.stat(ERROR_LOG_FILE);
    if (stats.size > MAX_ERROR_LOG_SIZE) {
      const rotated = ERROR_LOG_FILE + '.1';
      if (await exists(rotated)) {
        await fsp.unlink(rotated);
      }
      await fsp.rename(ERROR_LOG_FILE, rotated);
    }
  } catch (_) {
    // File may not exist yet, that's fine
  }
}

/**
 * Return a safe error message to the client without leaking internals
 */
function safeErrorMessage(error) {
  const msg = error.message || String(error);

  // Detect port conflict errors from Docker
  const portMatch = msg.match(/exposing port TCP [^:]*:(\d+)/);
  if (portMatch || msg.includes('port is already allocated') || msg.includes('ports are not available')) {
    const port = portMatch ? portMatch[1] : 'requested';
    return `Port ${port} is already in use. Please choose a different port or stop the conflicting service.`;
  }

  // Detect container not found errors
  if (msg.includes('No such container')) {
    return 'Container not found';
  }

  // Detect network errors
  if (msg.includes('ECONNREFUSED') || msg.includes('ETIMEDOUT')) {
    return 'Service unavailable';
  }

  // Generic safe message for unknown errors
  if (process.env.NODE_ENV === 'production') {
    return 'An error occurred. Please try again or contact support.';
  }

  // In development, show the actual error
  return msg;
}

module.exports = {
  logError,
  safeErrorMessage
};
