module AliyunVod::Sign
  # https://help.aliyun.com/document_detail/44434.html?spm=a2c4g.11186623.2.16.354c7853oqlhMb&/#SignatureNonce
  def self.generate(params, **opts)
    method = opts[:method] || 'POST'
    key = opts[:key] || AliyunVod.access_key_secret + '&'
    digest = OpenSSL::Digest.new('sha1')

    str = params_to_string(params)
    str = percent_encode(str)
    str = "#{method}&%2F&#{str}"

    Base64.encode64(OpenSSL::HMAC.digest(digest, key, str)).gsub(/\n/, '')
  end

  def self.verify?(signature, timestamp)
    content = "#{AliyunVod.callback_url}|#{timestamp}|#{AliyunVod.signature_key}"
    our_signature = Digest::MD5.hexdigest(content)
    ActiveSupport::SecurityUtils.secure_compare(signature, our_signature)
  end

  def self.params_to_string(params)
    params.sort.map { |k, v| "#{percent_encode(k)}=#{percent_encode(v)}" }.join('&')
  end

  def self.percent_encode(str)
    return '' if str.blank?
    CGI::escape(str.to_s).gsub(/\+/,'%20').gsub(/\*/,'%2A').gsub(/%7E/,'~')
  end

  def self.format_params(params)
    params.each_with_object({}) do |arr, obj|
      obj[arr[0]] = arr[1].is_a?(Hash) ? parse_hash_to_str(arr[1]) : arr[1]
    end
  end

  def self.parse_hash_to_str(hash)
    hash.each_with_object({}) do |h, obj|
      obj[h[0]] = h[1].is_a?(Hash) ? parse_hash_to_str(h[1].clone) : h[1].to_s
    end.to_json
  end
end