/**
 * Logging utilities - Structured logging and error handling
 */
const fsp = require('fs').promises;
const path = require('path');

const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };

/**
 * Create a structured logger
 */
function createLogger(LOG_LEVEL) {
  function log(level, context, message, data = {}) {
    if (LOG_LEVELS[level] < LOG_LEVEL) return;
    
    const entry = {
      t: new Date().toISOString(),
      level,
      ctx: context,
      msg: message,
    };
    
    if (Object.keys(data).length) entry.data = data;
    
    const fn = level === 'error' ? console.error : level === 'warn' ? console.warn : console.info;
    fn(JSON.stringify(entry));
  }
  
  log.info = (ctx, msg, data) => log('info', ctx, msg, data);
  log.warn = (ctx, msg, data) => log('warn', ctx, msg, data);
  log.error = (ctx, msg, data) => log('error', ctx, msg, data);
  log.debug = (ctx, msg, data) => log('debug', ctx, msg, data);
  
  return log;
}

/**
 * Enhanced error logging with context tracking
 */
async function logError(ERROR_LOG_FILE, MAX_ERROR_LOG_SIZE, context, error, additionalInfo = {}, log) {
  const timestamp = new Date().toISOString();

  // Extract request context
  const requestContext = {};
  if (additionalInfo.req) {
    const req = additionalInfo.req;
    const clientIP = req.ip || req.socket?.remoteAddress || '';
    requestContext.requestId = req.id;
    requestContext.ip = clientIP;
    requestContext.userAgent = req.get('user-agent');
    requestContext.method = req.method;
    requestContext.path = req.path;
    delete additionalInfo.req;
  }

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

  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
    try {
      const stats = await fsp.stat(ERROR_LOG_FILE);
      if (stats.size > MAX_ERROR_LOG_SIZE) {
        const rotated = ERROR_LOG_FILE + '.1';
        const exists = await fsp.access(rotated).then(() => true).catch(() => false);
        if (exists) await fsp.unlink(rotated);
        await fsp.rename(ERROR_LOG_FILE, rotated);
      }
    } catch (_) { /* file may not exist yet */ }
    
    await fsp.appendFile(ERROR_LOG_FILE, logLine);
  } catch (e) {
    if (log && log.error) {
      log.error('errorlog', 'Failed to write to error log', { error: e.message });
    }
  }
}

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

  // Detect port conflict errors
  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 `[DC-200] Port ${port} is already in use. Try a different port or stop the service using that port first.`;
  }

  // Only expose short, user-facing messages
  if (msg.length < 200 && !msg.includes('/') && !msg.includes('\\') && !msg.includes(' at ')) {
    return msg;
  }
  
  return 'An internal error occurred';
}

module.exports = {
  LOG_LEVELS,
  createLogger,
  logError,
  safeErrorMessage,
};
