# -*- coding: utf-8 -*- #
# frozen_string_literal: true

require_relative "../task_helper"
require 'json'

GHERKIN_KEYWORDS_FILE = "./lib/rouge/lexers/gherkin/keywords.rb"

namespace :builtins do
  task :gherkin do
    GherkinBuiltins.process(GHERKIN_KEYWORDS_FILE)
  end
end

class GherkinBuiltins < BuiltinsGenerator
  GHERKIN_SYNTAX_URI = "https://raw.githubusercontent.com/cucumber/gherkin/main/gherkin-languages.json"

  def fetch
    JSON.load(URI.open(GHERKIN_SYNTAX_URI))
  end

  def parse
    keywords = Hash.new { |h,k| h[k] = Set.new }

    @input.values.each do |lang|
      lang.each do |k,v|
        case k
        when "feature"
          keywords[:feature].merge v
        when "background", "rule", "scenario", "scenarioOutline"
          keywords[:element].merge v
        when "examples"
          keywords[:examples].merge v
        when "given", "when", "then", "and", "but"
          keywords[:step].merge v
        end
      end
    end

    keywords.transform_values { |v| v.map(&:strip) }
  end

  def step_regex
    @keywords[:step].sort.uniq.map do |w|
      if /\p{Word}/ =~ w[-1]
        "#{Regexp.escape(w)}\\b"
      else
        Regexp.escape(w)
      end
    end.join('|')
  end

  def generate
    yield   "# -*- coding: utf-8 -*- #"
    yield   "# frozen_string_literal: true"
    yield   ""
    yield   "# DO NOT EDIT"
    yield   "# This file is automatically generated by `rake builtins:gherkin`."
    yield   "# See tasks/builtins/gherkin.rake for more info."
    yield   ""
    yield   "module Rouge"
    yield   "  module Lexers"
    yield   "    class Gherkin"
    yield   "      # [jneen] this giant regex is staying, because Gherkin step"
    yield   "      # keywords are so arbitrary that there is not a good simple"
    yield   "      # pattern to match all of them and check post-hoc."
    yield   "      STEP_REGEX = %r(#{step_regex})o"
    yield   ""
    yield   "      KEYWORDS = {}.tap do |k|"
    @keywords.each do |t, kws|
      next if t == :step
      yield "        k[#{t.inspect}] = Set.new #{kws.to_a.sort.uniq.inspect}"
    end
    yield   "      end"
    yield   "    end"
    yield   "  end"
    yield   "end"
  end
end
