# frozen_string_literal: true

require 'logger'
require 'singleton'
require 'fileutils'

# LogService - 日志服务
# 功能：
# 1. 日志记录在 log 目录下
# 2. 分文件，每个大小 2M
# 3. 保留最近 10 个文件，名称为 syslog.txt
# 4. 同时输出到控制台
#
# 隐性知识：
# - 使用 Ruby 标准库 Logger 的轮转功能
# - 配置多输出（文件 + 控制台）
# - 线程安全，使用 Singleton 模式
class LogService
  include Singleton

  # 日志级别
  LEVELS = {
    debug: Logger::DEBUG,
    info: Logger::INFO,
    warn: Logger::WARN,
    error: Logger::ERROR,
    fatal: Logger::FATAL
  }.freeze

  # 默认配置
  DEFAULT_CONFIG = {
    log_dir: 'log',
    log_file: 'syslog.txt',
    max_size: 2 * 1024 * 1024, # 2MB
    max_files: 10,
    level: :info
  }.freeze

  attr_reader :logger, :config

  class << self
    # 类方法代理
    %i[debug info warn error fatal].each do |level|
      define_method(level) do |message|
        instance.send(level, message)
      end
    end
  end

  def initialize
    @config = DEFAULT_CONFIG.dup
    setup_logger
  end

  # 配置日志服务
  # @param [Hash] options 配置选项
  # @option options [String] :log_dir 日志目录
  # @option options [String] :log_file 日志文件名
  # @option options [Integer] :max_size 单个日志文件最大大小（字节）
  # @option options [Integer] :max_files 保留的日志文件数量
  # @option options [Symbol] :level 日志级别 (:debug, :info, :warn, :error, :fatal)
  def configure(options = {})
    @config.merge!(options)
    setup_logger
  end

  # 记录 debug 级别日志
  # @param [String] message 日志消息
  def debug(message)
    log(:debug, message)
  end

  # 记录 info 级别日志
  # @param [String] message 日志消息
  def info(message)
    log(:info, message)
  end

  # 记录 warn 级别日志
  # @param [String] message 日志消息
  def warn(message)
    log(:warn, message)
  end

  # 记录 error 级别日志
  # @param [String] message 日志消息
  def error(message)
    log(:error, message)
  end

  # 记录 fatal 级别日志
  # @param [String] message 日志消息
  def fatal(message)
    log(:fatal, message)
  end

  private

  # 设置日志器
  def setup_logger
    # 确保日志目录存在
    log_dir_path = File.expand_path(@config[:log_dir], File.join(__dir__, '..'))
    FileUtils.mkdir_p(log_dir_path) unless File.directory?(log_dir_path)

    # 日志文件路径
    log_file_path = File.join(log_dir_path, @config[:log_file])

    # 创建文件日志器，支持轮转
    file_logger = Logger.new(
      log_file_path,
      @config[:max_files],
      @config[:max_size]
    )

    # 创建控制台日志器
    console_logger = Logger.new($stdout)

    # 配置两个日志器的格式
    [file_logger, console_logger].each do |logger|
      logger.level = LEVELS[@config[:level]] || Logger::INFO
      logger.formatter = proc do |severity, datetime, _progname, msg|
        formatted_datetime = datetime.strftime('%Y-%m-%d %H:%M:%S')
        "[#{formatted_datetime}] [#{severity}] #{msg}\n"
      end
    end

    # 创建多输出日志器
    @logger = MultiLogger.new(file_logger, console_logger)
  end

  # 记录日志
  # @param [Symbol] level 日志级别
  # @param [String] message 日志消息
  def log(level, message)
    @logger.send(level, message)
  end

  # MultiLogger - 多输出日志器
  # 同时向多个日志器输出
  class MultiLogger
    def initialize(*loggers)
      @loggers = loggers
    end

    %i[debug info warn error fatal unknown].each do |level|
      define_method(level) do |message|
        @loggers.each { |logger| logger.send(level, message) }
      end

      define_method("#{level}?") do
        @loggers.any? { |logger| logger.send("#{level}?") }
      end
    end

    def level=(level)
      @loggers.each { |logger| logger.level = level }
    end

    def formatter=(formatter)
      @loggers.each { |logger| logger.formatter = formatter }
    end
  end
end
