import * as fs from 'fs/promises';
import * as path from 'path';

/**
 * 文件日志工具类
 * 支持按日期创建文件夹，按服务名称创建文件记录日志
 */
export class FileLogger {
  private logDir: string;
  private serviceName: string;

  /**
   * 构造函数
   * @param serviceName 服务名称，用于创建日志文件名
   * @param logDir 日志目录，默认为环境变量 LOG_DIR 或 './logs'
   */
  constructor(serviceName: string, logDir?: string) {
    this.serviceName = serviceName;
    this.logDir = logDir || process.env.LOG_DIR || './log-prd';
  }

  /**
   * 获取当前日期的文件夹路径 (格式: YYYY-MM-DD)
   */
  private getDateFolderPath(): string {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    return path.join(this.logDir, `${year}-${month}-${day}`);
  }

  /**
   * 获取日志文件路径
   */
  private getLogFilePath(): string {
    const dateFolder = this.getDateFolderPath();
    return path.join(dateFolder, `${this.serviceName}.log`);
  }

  /**
   * 确保日志目录存在
   */
  private async ensureLogDir(): Promise<void> {
    const logFilePath = this.getLogFilePath();
    const logDir = path.dirname(logFilePath);

    try {
      await fs.mkdir(logDir, { recursive: true });
    } catch (error) {
      console.error(`创建日志目录失败: ${error}`);
      throw error;
    }
  }

  /**
   * 格式化日志消息
   * @param level 日志级别
   * @param message 日志消息
   * @param metadata 元数据
   */
  private formatMessage(level: string, message: string, metadata?: any): string {
    const now = new Date();
    const timestamp = now.toISOString();
    const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;

    if (metadata) {
      const metadataStr = typeof metadata === 'object'
        ? JSON.stringify(metadata, null, 2)
        : String(metadata);
      return `${formattedMessage}\n${metadataStr}\n`;
    }

    return `${formattedMessage}\n`;
  }

  /**
   * 写入日志到文件
   * @param level 日志级别
   * @param message 日志消息
   * @param metadata 元数据
   */
  private async writeToFile(level: string, message: string, metadata?: any): Promise<void> {
    try {
      await this.ensureLogDir();
      const logFilePath = this.getLogFilePath();
      const formattedMessage = this.formatMessage(level, message, metadata);

      await fs.appendFile(logFilePath, formattedMessage, 'utf8');
    } catch (error) {
      console.error(`写入日志文件失败: ${error}`);
      // 不抛出错误，避免影响主流程
    }
  }

  /**
   * 记录信息级别日志
   * @param message 日志消息
   * @param metadata 元数据
   */
  async info(message: string, metadata?: any): Promise<void> {
    console.log(`[INFO] ${message}`, metadata || '');
    await this.writeToFile('info', message, metadata);
  }

  /**
   * 记录警告级别日志
   * @param message 日志消息
   * @param metadata 元数据
   */
  async warn(message: string, metadata?: any): Promise<void> {
    console.warn(`[WARN] ${message}`, metadata || '');
    await this.writeToFile('warn', message, metadata);
  }

  /**
   * 记录错误级别日志
   * @param message 日志消息
   * @param metadata 元数据
   */
  async error(message: string, metadata?: any): Promise<void> {
    console.error(`[ERROR] ${message}`, metadata || '');
    await this.writeToFile('error', message, metadata);
  }

  /**
   * 记录调试级别日志
   * @param message 日志消息
   * @param metadata 元数据
   */
  async debug(message: string, metadata?: any): Promise<void> {
    console.debug(`[DEBUG] ${message}`, metadata || '');
    await this.writeToFile('debug', message, metadata);
  }

  /**
   * 记录日志（通用方法）
   * @param level 日志级别
   * @param message 日志消息
   * @param metadata 元数据
   */
  async log(level: 'info' | 'warn' | 'error' | 'debug', message: string, metadata?: any): Promise<void> {
    switch (level) {
      case 'info':
        await this.info(message, metadata);
        break;
      case 'warn':
        await this.warn(message, metadata);
        break;
      case 'error':
        await this.error(message, metadata);
        break;
      case 'debug':
        await this.debug(message, metadata);
        break;
    }
  }
}

/**
 * 创建服务日志器实例
 * @param serviceName 服务名称
 * @param logDir 日志目录，默认为环境变量 LOG_DIR 或 './logs'
 * @returns FileLogger 实例
 */
export function createServiceLogger(serviceName: string, logDir?: string): FileLogger {
  return new FileLogger(serviceName, logDir);
}