// logger.js
const fs = require('fs');
const path = require('path');

class Logger {
  constructor(options = {}) {
    // Dynamically determine the base directory
    const isPackaged = process.pkg !== undefined;
    let baseDir;

    if (isPackaged) {
      // If running as a packaged executable, use the directory where the executable is located
      baseDir = path.dirname(process.execPath);
    } else {
      // In development, use the project root directory
      baseDir = process.cwd();
    }

    this.options = {
      logToConsole: options.logToConsole !== false,
      logToFile: options.logToFile || false,
      // Use the determined base directory + logs
      logDirectory: options.logDirectory || path.join(baseDir, 'logs'),
      userActivityLogFile: options.userActivityLogFile || 'user-activity.log',
      apiLogFile: options.apiLogFile || 'api.log',
      minLevel: options.minLevel || 'info',
    };

    // Create log directory if it doesn't exist and logging to file is enabled
    if (this.options.logToFile) {
      try {
        if (!fs.existsSync(this.options.logDirectory)) {
          fs.mkdirSync(this.options.logDirectory, { recursive: true });
        }
      } catch (err) {
        console.error(`Failed to create log directory: ${err.message}`);
        // Fall back to logging in the same directory as the executable if directory creation fails
        this.options.logDirectory = baseDir;
        console.log(`Falling back to logging in: ${this.options.logDirectory}`);
      }
    }

    // Log levels and their priorities
    this.levels = {
      debug: 0,
      info: 1,
      warn: 2,
      error: 3,
    };
  }

  shouldLog(level) {
    return this.levels[level] >= this.levels[this.options.minLevel];
  }

  formatLogEntry(type, message, data = {}) {
    const timestamp = global.Utils.toIsoString(new Date());
    const logObject = {
      timestamp,
      type,
      message,
    };

    if (Object.keys(data).length > 0) {
      logObject.data = data;
    }

    return JSON.stringify(logObject);
  }

  writeToFile(content, isUserActivity = false) {
    if (!this.options.logToFile) return;

    const logFile =
      isUserActivity ?
        path.join(this.options.logDirectory, this.options.userActivityLogFile)
      : path.join(this.options.logDirectory, this.options.apiLogFile);

    // Check if the log directory exists before writing
    try {
      // Ensure the directory exists
      if (!fs.existsSync(this.options.logDirectory)) {
        fs.mkdirSync(this.options.logDirectory, { recursive: true });
        console.log(`Log directory recreated at: ${this.options.logDirectory}`);
      }

      // Now write the log
      fs.appendFileSync(logFile, content + '\n');
    } catch (err) {
      console.error(`Error writing to log file: ${err.message}`);
      // Fall back to console logging if file writing fails
      if (this.options.logToConsole) {
        console.log(
          `Failed to write to log file, logging to console instead: ${content}`
        );
      }
    }
  }

  debug(message, data = {}) {
    if (!this.shouldLog('debug')) return;

    const logEntry = this.formatLogEntry('DEBUG', message, data);

    if (this.options.logToConsole) {
      console.debug(logEntry);
    }

    this.writeToFile(logEntry);
  }

  info(message, data = {}) {
    if (!this.shouldLog('info')) return;

    const logEntry = this.formatLogEntry('INFO', message, data);

    if (this.options.logToConsole) {
      console.log(logEntry);
    }

    this.writeToFile(logEntry);
  }

  warn(message, data = {}) {
    if (!this.shouldLog('warn')) return;

    const logEntry = this.formatLogEntry('WARN', message, data);

    if (this.options.logToConsole) {
      console.warn(logEntry);
    }

    this.writeToFile(logEntry);
  }

  error(message, data = {}) {
    if (!this.shouldLog('error')) return;

    const logEntry = this.formatLogEntry('ERROR', message, data);

    if (this.options.logToConsole) {
      console.error(logEntry);
    }

    this.writeToFile(logEntry);
  }

  // Specialized method for user activity logging
  userActivity(eventType, data = {}) {
    const logEntry = this.formatLogEntry('USER_ACTIVITY', eventType, data);

    // Don't log user activity to the console
    /*
    if (this.options.logToConsole) {
      console.log(`[USER_ACTIVITY] ${logEntry}`);
    }
    */

    this.writeToFile(logEntry, true);
  }
}

// Create and export default logger instance
const defaultLogger = new Logger({
  logToConsole: true,
  logToFile: true,
  minLevel: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
});

module.exports = {
  Logger,
  logger: defaultLogger,
};
