#!/usr/bin/env ruby

require_relative 'shared_constants'

# Error handling and logging module
module ErrorHandler
  extend self

  # Handle parsing errors with context
  def handle_parsing_error(error, context = nil, options = {})
    message = build_error_message(error, context)
    
    case options[:action]
    when :log_only
      log_error(message)
      nil
    when :raise
      log_error(message)
      raise error
    else
      log_error(message)
      options[:default]
    end
  end

  # Safe parsing with error handling
  def safe_parse(value, type, default = nil)
    return default if value.nil?
    
    case type
    when :time
      parse_time(value, default)
    when :datetime
      parse_datetime(value, default)
    when :date
      parse_date(value, default)
    when :float
      parse_float(value, default)
    when :integer
      parse_integer(value, default)
    when :year
      parse_year(value, default)
    when :boolean
      parse_boolean(value, default)
    else
      value.to_s
    end
  end

  # Handle CSV parsing errors
  def handle_csv_error(error, row_number = nil, options = {})
    context = row_number ? "CSV row #{row_number}" : "CSV parsing"
    
    case error
    when CSV::MalformedCSVError
      handle_parsing_error(error, context, options.merge(action: :log_only))
    when ArgumentError
      handle_parsing_error(error, context, options.merge(action: :log_only))
    else
      handle_parsing_error(error, context, options)
    end
  end

  # Handle database/file errors
  def handle_file_error(error, file_path = nil, options = {})
    context = file_path ? "file #{file_path}" : "file operation"
    
    case error
    when Errno::ENOENT
      log_error("File not found: #{file_path}")
      options[:default] || false
    when Errno::EACCES
      log_error("Permission denied: #{file_path}")
      options[:default] || false
    when Errno::ENOSPC
      log_error("No space left on device: #{file_path}")
      options[:default] || false
    else
      handle_parsing_error(error, context, options)
    end
  end

  # Handle network errors
  def handle_network_error(error, url = nil, options = {})
    context = url ? "network request to #{url}" : "network operation"
    
    case error
    when Net::TimeoutError
      log_error("Network timeout: #{url}")
      options[:default] || nil
    when Net::HTTPError
      log_error("HTTP error: #{error.message}")
      options[:default] || nil
    when SocketError
      log_error("Socket error: #{error.message}")
      options[:default] || nil
    else
      handle_parsing_error(error, context, options)
    end
  end

  # Handle IRC bot errors
  def handle_bot_error(error, command = nil, options = {})
    context = command ? "IRC command #{command}" : "IRC bot operation"
    
    case error
    when ArgumentError
      log_error("Invalid command arguments: #{command}")
      options[:default] || "Invalid command format"
    when SecurityError
      log_error("Security error in command: #{command}")
      options[:default] || "Access denied"
    else
      handle_parsing_error(error, context, options)
    end
  end

  # Validate and handle user input
  def validate_user_input(input, type, options = {})
    return handle_validation_error("Input is required", type, options) if input.nil?
    
    case type
    when :user
      validate_user(input, options)
    when :substance
      validate_substance(input, options)
    when :year
      validate_year(input, options)
    when :dose
      validate_dose(input, options)
    when :route
      validate_route(input, options)
    else
      input
    end
  end

  # Log error with timestamp and context
  def log_error(message, level = :error)
    timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
    
    case level
    when :debug
      puts "[DEBUG] #{timestamp}: #{message}" if debug_mode?
    when :info
      puts "[INFO] #{timestamp}: #{message}"
    when :warning
      puts "[WARNING] #{timestamp}: #{message}"
    when :error
      puts "[ERROR] #{timestamp}: #{message}"
    when :fatal
      puts "[FATAL] #{timestamp}: #{message}"
    end
  end

  # Check if operation succeeded
  def success?(result)
    !result.nil? && result != false
  end

  # Wrap operation with error handling
  def with_error_handling(operation_name, options = {})
    begin
      result = yield
      log_error("#{operation_name} completed successfully", :info) if options[:log_success]
      result
    rescue => error
      handle_parsing_error(error, operation_name, options)
    end
  end

  # Retry operation with exponential backoff
  def retry_with_backoff(max_retries = 3, base_delay = 1.0)
    retries = 0
    
    begin
      yield
    rescue => error
      retries += 1
      
      if retries <= max_retries
        delay = base_delay * (2 ** (retries - 1))
        log_error("Retry #{retries}/#{max_retries} after #{delay}s: #{error.message}", :warning)
        sleep(delay)
        retry
      else
        log_error("Max retries (#{max_retries}) exceeded: #{error.message}", :error)
        raise error
      end
    end
  end

  private

  # Build error message with context
  def build_error_message(error, context)
    base_message = "#{error.class}: #{error.message}"
    context ? "#{context} - #{base_message}" : base_message
  end

  # Parse time with error handling
  def parse_time(value, default)
    Time.parse(value.to_s)
  rescue ArgumentError, TypeError
    default
  end

  # Parse datetime with error handling
  def parse_datetime(value, default)
    DateTime.parse(value.to_s)
  rescue ArgumentError, TypeError
    default
  end

  # Parse date with error handling
  def parse_date(value, default)
    Date.parse(value.to_s)
  rescue ArgumentError, TypeError
    default
  end

  # Parse float with error handling
  def parse_float(value, default)
    Float(value.to_s)
  rescue ArgumentError, TypeError
    default
  end

  # Parse integer with error handling
  def parse_integer(value, default)
    Integer(value.to_s)
  rescue ArgumentError, TypeError
    default
  end

  # Parse year with validation
  def parse_year(value, default)
    year = parse_integer(value, nil)
    return default if year.nil?
    
    if year >= SharedConstants::Validation::MIN_YEAR && year <= SharedConstants::Validation::MAX_YEAR
      year
    else
      default
    end
  end

  # Parse boolean with error handling
  def parse_boolean(value, default)
    case value.to_s.downcase
    when 'true', '1', 'yes', 'on'
      true
    when 'false', '0', 'no', 'off'
      false
    else
      default
    end
  end

  # Validate user input
  def validate_user(input, options)
    input = input.to_s.strip
    
    if input.length < SharedConstants::Validation::MIN_USERNAME_LENGTH
      return handle_validation_error("Username too short", :user, options)
    end
    
    if input.length > SharedConstants::Validation::MAX_USERNAME_LENGTH
      return handle_validation_error("Username too long", :user, options)
    end
    
    unless input.match?(SharedConstants::Validation::USERNAME_PATTERN)
      return handle_validation_error("Invalid username format", :user, options)
    end
    
    input
  end

  # Validate substance input
  def validate_substance(input, options)
    input = input.to_s.strip
    
    if input.length < SharedConstants::Validation::MIN_SUBSTANCE_LENGTH
      return handle_validation_error("Substance name too short", :substance, options)
    end
    
    if input.length > SharedConstants::Validation::MAX_SUBSTANCE_LENGTH
      return handle_validation_error("Substance name too long", :substance, options)
    end
    
    input
  end

  # Validate year input
  def validate_year(input, options)
    year = parse_integer(input, nil)
    
    if year.nil?
      return handle_validation_error("Invalid year format", :year, options)
    end
    
    if year < SharedConstants::Validation::MIN_YEAR || year > SharedConstants::Validation::MAX_YEAR
      return handle_validation_error("Year out of range", :year, options)
    end
    
    year
  end

  # Validate dose input
  def validate_dose(input, options)
    input = input.to_s.strip
    return handle_validation_error("Dose is required", :dose, options) if input.empty?
    
    require_relative 'dose_processor'
    
    unless DoseProcessor.valid_dose_format?(input)
      return handle_validation_error("Invalid dose format", :dose, options)
    end
    
    input
  end

  # Validate route input
  def validate_route(input, options)
    return SharedConstants::Defaults::ROUTE if input.nil? || input.empty?
    input.to_s.strip
  end

  # Handle validation error
  def handle_validation_error(message, type, options)
    log_error("Validation error (#{type}): #{message}", :warning)
    options[:default] || nil
  end

  # Check if debug mode is enabled
  def debug_mode?
    ENV['DEBUG'] == 'true' || ENV['DEBUG'] == '1'
  end
end
