require 'markdown_helper/version'

# Helper class for working with GitHub markdown.
#  Supports file inclusion.
#
# @author Burdette Lamar
class MarkdownHelper

  IMAGE_REGEXP = /^!\[([^\[]+)\]\(([^)]+)\)/
  INCLUDE_REGEXP = /^@\[([^\[]+)\]\(([^)]+)\)/

  # Get the user name and repository name from ENV.
  def repo_user_and_name
    repo_user = ENV['REPO_USER']
    repo_name = ENV['REPO_NAME']
    unless repo_user and repo_name
      message = 'ENV values for both REPO_USER and REPO_NAME must be defined.'
      raise RuntimeError.new(message)
    end
    [repo_user, repo_name]
  end

  # Merges external files into markdown text.
  # @param template_file_path [String] the path to the input template markdown file, usually containing include pragmas.
  # @param markdown_file_path [String] the path to the output merged markdown file.
  # @return [String] the resulting markdown text.
  #
  # @example pragma to include text as a highlighted code block.
  #   @[ruby](foo.rb)
  #
  # @example pragma to include text as a plain code block.
  #   @[:code_block](foo.xyz)
  #
  # @example pragma to include text verbatim, to be rendered as markdown.
  #   @[:verbatim](foo.md)
  def include(template_file_path, markdown_file_path)
    output_lines = []
    File.open(template_file_path, 'r') do |template_file|
      template_file.each_line do |input_line|
        match_data = input_line.match(INCLUDE_REGEXP)
        unless match_data
          output_lines.push(input_line)
          next
        end
        treatment = case match_data[1]
                      when ':code_block'
                        :code_block
                      when ':verbatim'
                        :verbatim
                      else
                        match_data[1]
                    end
        relative_file_path = match_data[2]
        include_file_path = File.join(
            File.dirname(template_file_path),
            relative_file_path,
        )
        included_text = File.read(include_file_path)
        unless included_text.match("\n")
          message = "Warning:  Included file has no trailing newline: #{include_file_path}"
          warn(message)
        end
        if treatment == :verbatim
          # Pass through unadorned.
          output_lines.push(included_text)
        else
          # Use the file name as a label.
          file_name_line = format("<code>%s</code>\n", File.basename(include_file_path))
          output_lines.push(file_name_line)
          # Put into code block.
          language = treatment == :code_block ? '' : treatment
          output_lines.push("```#{language}\n")
          output_lines.push(included_text)
          output_lines.push("```\n")
        end
      end
    end
    output = output_lines.join('')
    File.open(markdown_file_path, 'w') do |md_file|
      md_file.write(output)
    end
    output
  end

  # Resolves relative image paths to absolute urls in markdown text.
  # @param template_file_path [String] the path to the input template markdown file, usually containing image pragmas.
  # @param markdown_file_path [String] the path to the output resolved markdown file.
  # @return [String] the resulting markdown text.
  #
  # This matters because when markdown becomes part of a Ruby gem,
  # its images will have been relocated in the documentation at RubyDoc.info, breaking the paths.
  # The resolved (absolute) urls, however, will still be valid.
  #
  # ENV['REPO_USER'] and ENV['REPO_NAME'] must give the user name and repository name of the relevant GitHub repository.
  #  must give the repo name of the relevant GitHub repository.
  #
  # @example pragma for an image:
  #   ![image_icon](images/image.png)
  #
  # The path resolves to:
  #
  #   absolute_file_path = File.join(
  #       "https://raw.githubusercontent.com/#{repo_user}/#{repo_name}/master",
  #       relative_file_path,
  #   )
  def resolve_image_urls(template_file_path, markdown_file_path)
    output_lines = []
    File.open(template_file_path, 'r') do |template_file|
      output_lines = []
      template_file.each_line do |input_line|
        match_data = input_line.match(IMAGE_REGEXP)
        unless match_data
          output_lines.push(input_line)
          next
        end
        alt_text = match_data[1]
        relative_file_path, attributes_s = match_data[2].split(/\s?\|\s?/, 2)
        attributes = attributes_s ? attributes_s.split(/\s+/) : []
        formatted_attributes = ['']
        attributes.each do |attribute|
          name, value = attribute.split('=', 2)
          formatted_attributes.push(format('%s="%s"', name, value))
        end
        formatted_attributes_s = formatted_attributes.join(' ')
        repo_user, repo_name = repo_user_and_name
        absolute_file_path = File.join(
            "https://raw.githubusercontent.com/#{repo_user}/#{repo_name}/master",
            relative_file_path,
        )
        line = format('<img src="%s" alt="%s"%s>', absolute_file_path, alt_text, formatted_attributes_s) + "\n"
        output_lines.push(line)
      end
    end
    output = output_lines.join('')
    File.open(markdown_file_path, 'w') do |md_file|
      md_file.write(output)
    end
    output
  end

end