# apps/api/v1/utils.rb

module V1
  # V1::Utils - a local copy of the Onetime::Utils of old.
  #
  # Note: there are limitations to these implementations that existed in the
  # Onetime::Utils module for many years. We have made improvements and
  # alternative approaches to address these limitations in Onetime::Utils.
  # and related code that are not featured here. For example we are using
  # refinements for indifferent hash access rather than mucking directly
  # with the Hash instances.
  #
  module Utils
    extend self

    using Familia::Refinements::TimeLiterals

    unless defined?(VALID_CHARS)
      VALID_CHARS = [('a'..'z').to_a, ('A'..'Z').to_a, ('0'..'9').to_a, %w[* $ ! ? ( )]].flatten
      VALID_CHARS_SAFE = VALID_CHARS.clone
      VALID_CHARS_SAFE.delete_if { |v| %w[i l o 1 0].member?(v) }
      VALID_CHARS.freeze
      VALID_CHARS_SAFE.freeze
    end
    attr_accessor :fortunes

    def random_fortune
      raise OT::Problem, "No fortunes" if fortunes.nil?
      raise OT::Problem, "#{fortunes.class} is not an Array" unless fortunes.is_a?(Array)
      fortune = fortunes.sample.to_s.strip
      raise OT::Problem, "No fortune found" if fortune.empty?
      fortune
    rescue OT::Problem => e
      OT.le "#{e.message}"
      'Unexpected outcomes bring valuable lessons.'
    rescue StandardError => e
      OT.le "#{e.message} (#{fortunes.class})"
      OT.ld "#{e.backtrace.join("\n")}"
      'A house is full of games and puzzles.'
    end

    # WARNING: Using rand(chars.size - 1) excludes the last element and biases selection;
    # use rand(chars.size) or chars.sample instead.
    # We won't change this in v1 for compatibility reasons.
    def strand(len = 12, safe = true)
      chars = safe ? VALID_CHARS_SAFE : VALID_CHARS
      (1..len).collect { chars[rand(chars.size - 1)] }.join
    end

    def obscure_email(text)
      regex = /(\b(([A-Z0-9]{1,2})[A-Z0-9._%-]*)([A-Z0-9])?(@([A-Z0-9])[A-Z0-9.-]+(\.[A-Z]{2,4}\b)))/i
      el = text.split('@')
      text.gsub regex, '\\3*****\\4@\\6*****\\7'
    end

  end

  module TimeUtils
    extend self

      def natural_duration(duration_in_s)
        if duration_in_s <= 1.minute
          '%d seconds' % duration_in_s
        elsif duration_in_s <= 1.hour
          '%d minutes' % duration_in_s.in_minutes
        elsif duration_in_s <= 1.day
          '%d hours' % duration_in_s.in_hours
        else
          '%d days' % duration_in_s.in_days
        end
      end

      # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
      def natural_time(time_in_s)
        return if time_in_s.nil?

        val = Time.now.utc.to_i - time_in_s.to_i

        if val < 10
          result = 'a moment ago'
        elsif val < 40
          result = "about #{(val * 1.5).to_i.to_s.slice(0, 1)}0 seconds ago"
        elsif val < 60
          result = 'about a minute ago'
        elsif val < 60 * 1.3
          result = '1 minute ago'
        elsif val < 60 * 2
          result = '2 minutes ago'
        elsif val < 60 * 50
          result = "#{(val / 60).to_i} minutes ago"
        elsif val < 3600 * 1.4
          result = 'about 1 hour ago'
        elsif val < 3600 * (24 / 1.02)
          result = "about #{(val / 60 / 60 * 1.02).to_i} hours ago"
        elsif val < 3600 * 24 * 1.6
          result = Time.at(time_in_s.to_i).strftime('yesterday').downcase
        elsif val < 3600 * 24 * 7
          result = Time.at(time_in_s.to_i).strftime('on %A').downcase
        else
          weeks = (val / 3600.0 / 24.0 / 7).to_i
          result = Time.at(time_in_s.to_i).strftime("#{weeks} #{weeks == 1 ? 'week' : 'weeks'} ago").downcase
        end
        result
      end
    # rubocop:enable Metrics/PerceivedComplexity, Metrics/AbcSize
  end
end
