# frozen_string_literal: true
INLINE_SCRIPT_REGEX = /(<script(\s*(?!src)([\w\-])+=([\"\'])[^\"\']+\4)*\s*>)(.*?)<\/script>/mx unless defined? INLINE_SCRIPT_REGEX
INLINE_STYLE_REGEX = /(<style[^>]*>)(.*?)<\/style>/mx unless defined? INLINE_STYLE_REGEX
INLINE_HASH_SCRIPT_HELPER_REGEX = /<%=\s?hashed_javascript_tag(.*?)\s+do\s?%>(.*?)<%\s*end\s*%>/mx unless defined? INLINE_HASH_SCRIPT_HELPER_REGEX
INLINE_HASH_STYLE_HELPER_REGEX = /<%=\s?hashed_style_tag(.*?)\s+do\s?%>(.*?)<%\s*end\s*%>/mx unless defined? INLINE_HASH_STYLE_HELPER_REGEX

namespace :secure_headers do
  include SecureHeaders::HashHelper

  def is_erb?(filename)
    filename =~ /\.erb\Z/
  end

  def is_mustache?(filename)
    filename =~ /\.mustache\Z/
  end

  def dynamic_content?(filename, inline_script)
    (is_mustache?(filename) && inline_script =~ /\{\{.*\}\}/) ||
      (is_erb?(filename) && inline_script =~ /<%.*%>/)
  end

  def find_inline_content(filename, regex, hashes, strip_trailing_whitespace)
    file = File.read(filename)
    file.scan(regex) do # TODO don't use gsub
      inline_script = Regexp.last_match.captures.last
      inline_script.gsub!(/(\r?\n)[\t ]+\z/, '\1') if strip_trailing_whitespace
      if dynamic_content?(filename, inline_script)
        puts "Looks like there's some dynamic content inside of a tag :-/"
        puts "That pretty much means the hash value will never match."
        puts "Code: " + inline_script
        puts "=" * 20
      end

      hashes << hash_source(inline_script)
    end
  end

  def generate_inline_script_hashes(filename)
    hashes = []

    find_inline_content(filename, INLINE_SCRIPT_REGEX, hashes, false)
    find_inline_content(filename, INLINE_HASH_SCRIPT_HELPER_REGEX, hashes, true)

    hashes
  end

  def generate_inline_style_hashes(filename)
    hashes = []

    find_inline_content(filename, INLINE_STYLE_REGEX, hashes, false)
    find_inline_content(filename, INLINE_HASH_STYLE_HELPER_REGEX, hashes, true)

    hashes
  end

  desc "Generate #{SecureHeaders::Configuration::HASH_CONFIG_FILE}"
  task :generate_hashes do |t, args|
    script_hashes = {
      "scripts" => {},
      "styles" => {}
    }

    Dir.glob("app/{views,templates}/**/*.{erb,mustache}") do |filename|
      hashes = generate_inline_script_hashes(filename)
      if hashes.any?
        script_hashes["scripts"][filename] = hashes
      end

      hashes = generate_inline_style_hashes(filename)
      if hashes.any?
        script_hashes["styles"][filename] = hashes
      end
    end

    File.open(SecureHeaders::Configuration::HASH_CONFIG_FILE, "w") do |file|
      file.write(script_hashes.to_yaml)
    end

    puts "Script hashes from " + script_hashes.keys.size.to_s + " files added to #{SecureHeaders::Configuration::HASH_CONFIG_FILE}"
  end
end
