import { createWriteStream, WriteStream, existsSync, mkdirSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'

export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical'

export interface LogEntry {
  timestamp: string
  level: LogLevel
  module: string
  message: string
  metadata?: Record<string, any>
  traceId?: string
  userId?: string
  exchange?: string
  accountId?: string
}

export interface LoggerConfig {
  level: LogLevel
  enableConsole: boolean
  enableFile: boolean
  logDir?: string
  maxFileSize?: number // MB
  maxFiles?: number
  enableRotation?: boolean
  enableAudit?: boolean
}

export class ProductionLogger {
  private config: LoggerConfig
  private logStream?: WriteStream
  private auditStream?: WriteStream
  private currentLogFile?: string
  private currentFileSize = 0
  private static instance?: ProductionLogger

  constructor(config: Partial<LoggerConfig> = {}) {
    this.config = {
      level: 'info',
      enableConsole: true,
      enableFile: true,
      logDir: './logs',
      maxFileSize: 100, // 100MB
      maxFiles: 10,
      enableRotation: true,
      enableAudit: true,
      ...config,
    }

    this.initializeLogDirectory()
    this.initializeLogStreams()
  }

  /**
   * 获取单例实例
   */
  static getInstance(config?: Partial<LoggerConfig>): ProductionLogger {
    if (!ProductionLogger.instance) {
      ProductionLogger.instance = new ProductionLogger(config)
    }
    return ProductionLogger.instance
  }

  /**
   * 初始化日志目录
   */
  private initializeLogDirectory(): void {
    if (this.config.enableFile && this.config.logDir) {
      if (!existsSync(this.config.logDir)) {
        mkdirSync(this.config.logDir, { recursive: true })
      }
    }
  }

  /**
   * 初始化日志流
   */
  private initializeLogStreams(): void {
    if (this.config.enableFile && this.config.logDir) {
      const timestamp = new Date().toISOString().split('T')[0]

      // 主日志文件
      this.currentLogFile = join(this.config.logDir, `trading-system-${timestamp}.log`)
      this.logStream = createWriteStream(this.currentLogFile, { flags: 'a' })

      // 审计日志文件
      if (this.config.enableAudit) {
        const auditFile = join(this.config.logDir, `audit-${timestamp}.log`)
        this.auditStream = createWriteStream(auditFile, { flags: 'a' })
      }
    }
  }

  /**
   * 记录 Debug 级别日志
   */
  debug(message: string, metadata?: Record<string, any>, module = 'SYSTEM'): void {
    this.log('debug', module, message, metadata)
  }

  /**
   * 记录 Info 级别日志
   */
  info(message: string, metadata?: Record<string, any>, module = 'SYSTEM'): void {
    this.log('info', module, message, metadata)
  }

  /**
   * 记录 Warning 级别日志
   */
  warn(message: string, metadata?: Record<string, any>, module = 'SYSTEM'): void {
    this.log('warn', module, message, metadata)
  }

  /**
   * 记录 Error 级别日志
   */
  error(message: string, error?: Error | any, metadata?: Record<string, any>, module = 'SYSTEM'): void {
    const errorMetadata = {
      ...metadata,
      ...(error && {
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
      }),
    }
    this.log('error', module, message, errorMetadata)
  }

  /**
   * 记录 Critical 级别日志
   */
  critical(message: string, error?: Error | any, metadata?: Record<string, any>, module = 'SYSTEM'): void {
    const errorMetadata = {
      ...metadata,
      ...(error && {
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
      }),
    }
    this.log('critical', module, message, errorMetadata)
  }

  /**
   * 记录交易相关日志
   */
  trade(
    action: string,
    details: {
      exchange: string
      accountId?: string
      symbol?: string
      side?: string
      quantity?: string
      price?: string
      orderId?: string
      [key: string]: any
    },
  ): void {
    this.log('info', 'TRADING', `交易操作: ${action}`, {
      ...details,
      category: 'trading',
    })
  }

  /**
   * 记录对冲相关日志
   */
  hedge(
    action: string,
    details: {
      sourceExchange: string
      targetExchange: string
      symbol: string
      quantity: string
      reason: string
      [key: string]: any
    },
  ): void {
    this.log('info', 'HEDGING', `对冲操作: ${action}`, {
      ...details,
      category: 'hedging',
    })
  }

  /**
   * 记录账户相关日志
   */
  account(
    action: string,
    details: {
      exchange: string
      accountId: string
      [key: string]: any
    },
  ): void {
    this.log('info', 'ACCOUNT', `账户操作: ${action}`, {
      ...details,
      category: 'account',
    })
  }

  /**
   * 记录 WebSocket 相关日志
   */
  websocket(
    action: string,
    details: {
      exchange: string
      event?: string
      symbol?: string
      [key: string]: any
    },
  ): void {
    this.log('info', 'WEBSOCKET', `WebSocket事件: ${action}`, {
      ...details,
      category: 'websocket',
    })
  }

  /**
   * 记录性能相关日志
   */
  performance(metric: string, value: number, details?: Record<string, any>): void {
    this.log('info', 'PERFORMANCE', `性能指标: ${metric}`, {
      metric,
      value,
      unit: 'ms',
      ...details,
      category: 'performance',
    })
  }

  /**
   * 记录审计日志
   */
  audit(
    action: string,
    details: {
      userId?: string
      exchange?: string
      accountId?: string
      resource: string
      result: 'success' | 'failure'
      [key: string]: any
    },
  ): void {
    const auditEntry = {
      timestamp: new Date().toISOString(),
      action,
      ...details,
      category: 'audit',
    }

    // 同时写入主日志和审计日志
    this.log('info', 'AUDIT', `审计操作: ${action}`, auditEntry)

    if (this.auditStream) {
      this.auditStream.write(JSON.stringify(auditEntry) + '\n')
    }
  }

  /**
   * 核心日志记录方法
   */
  private log(level: LogLevel, module: string, message: string, metadata?: Record<string, any>): void {
    // 检查日志级别
    if (!this.shouldLog(level)) {
      return
    }

    const logEntry: LogEntry = {
      timestamp: new Date().toISOString(),
      level,
      module,
      message,
      metadata,
    }

    // 控制台输出
    if (this.config.enableConsole) {
      this.outputToConsole(logEntry)
    }

    // 文件输出
    if (this.config.enableFile && this.logStream) {
      this.outputToFile(logEntry)
    }

    // 检查文件轮转
    if (this.config.enableRotation && this.shouldRotate()) {
      this.rotateLogFile()
    }
  }

  /**
   * 检查是否应该记录该级别的日志
   */
  private shouldLog(level: LogLevel): boolean {
    const levels = ['debug', 'info', 'warn', 'error', 'critical']
    const currentLevelIndex = levels.indexOf(this.config.level)
    const messageLevelIndex = levels.indexOf(level)
    return messageLevelIndex >= currentLevelIndex
  }

  /**
   * 输出到控制台
   */
  private outputToConsole(entry: LogEntry): void {
    const coloredLevel = this.getColoredLevel(entry.level)
    const timestamp = entry.timestamp.split('T')[1].split('.')[0] // 只显示时间部分

    let output = `${timestamp} ${coloredLevel} [${entry.module}] ${entry.message}`

    if (entry.metadata) {
      const metadataStr = JSON.stringify(entry.metadata, null, 2)
        .split('\n')
        .map(line => `  ${line}`)
        .join('\n')
      output += `\n${metadataStr}`
    }

    // 根据级别选择输出方式
    switch (entry.level) {
      case 'error':
      case 'critical':
        console.error(output)
        break
      case 'warn':
        console.warn(output)
        break
      default:
        console.log(output)
    }
  }

  /**
   * 输出到文件
   */
  private outputToFile(entry: LogEntry): void {
    if (!this.logStream) return

    const logLine = JSON.stringify(entry) + '\n'
    this.logStream.write(logLine)
    this.currentFileSize += Buffer.byteLength(logLine)
  }

  /**
   * 获取带颜色的日志级别
   */
  private getColoredLevel(level: LogLevel): string {
    const colors = {
      debug: '\x1b[90m', // 灰色
      info: '\x1b[32m', // 绿色
      warn: '\x1b[33m', // 黄色
      error: '\x1b[31m', // 红色
      critical: '\x1b[41m', // 红色背景
    }

    const reset = '\x1b[0m'
    return `${colors[level]}${level.toUpperCase().padEnd(8)}${reset}`
  }

  /**
   * 检查是否需要轮转日志文件
   */
  private shouldRotate(): boolean {
    const maxSizeBytes = (this.config.maxFileSize || 100) * 1024 * 1024
    return this.currentFileSize > maxSizeBytes
  }

  /**
   * 轮转日志文件
   */
  private rotateLogFile(): void {
    if (this.logStream) {
      this.logStream.end()
    }

    if (this.auditStream) {
      this.auditStream.end()
    }

    this.currentFileSize = 0
    this.initializeLogStreams()

    this.info(
      '日志文件已轮转',
      {
        newLogFile: this.currentLogFile,
      },
      'LOGGER',
    )
  }

  /**
   * 创建子日志器
   */
  child(module: string, baseMetadata?: Record<string, any>) {
    return {
      debug: (message: string, metadata?: Record<string, any>) =>
        this.debug(message, { ...baseMetadata, ...metadata }, module),
      info: (message: string, metadata?: Record<string, any>) =>
        this.info(message, { ...baseMetadata, ...metadata }, module),
      warn: (message: string, metadata?: Record<string, any>) =>
        this.warn(message, { ...baseMetadata, ...metadata }, module),
      error: (message: string, error?: Error, metadata?: Record<string, any>) =>
        this.error(message, error, { ...baseMetadata, ...metadata }, module),
      critical: (message: string, error?: Error, metadata?: Record<string, any>) =>
        this.critical(message, error, { ...baseMetadata, ...metadata }, module),
    }
  }

  /**
   * 关闭日志器
   */
  close(): void {
    if (this.logStream) {
      this.logStream.end()
    }
    if (this.auditStream) {
      this.auditStream.end()
    }
  }

  /**
   * 获取统计信息
   */
  getStats() {
    return {
      config: this.config,
      currentLogFile: this.currentLogFile,
      currentFileSize: this.currentFileSize,
      streamActive: !!this.logStream && !this.logStream.destroyed,
    }
  }
}

// 创建默认的全局日志器实例
export const logger = ProductionLogger.getInstance({
  level: (process.env.LOG_LEVEL as LogLevel) || 'info',
  enableConsole: process.env.NODE_ENV !== 'test',
  enableFile: process.env.NODE_ENV === 'production',
  logDir: process.env.LOG_DIR || './logs',
})
