defmodule Mix.Tasks.GenerateEntities do
  @shortdoc "Generate the entities module"

  @json_entities_path "priv/entities.json"
  @destination_module_path "lib/floki/entities/codepoints.ex"

  use Mix.Task

  @impl Mix.Task
  def run(_) do
    Mix.shell().info("Generating entities..")

    {:ok, content} = File.read(@json_entities_path)
    {:ok, json} = Jason.decode(content)

    headers = """
    defmodule Floki.Entities.Codepoints do
    # This file was generated by "Mix.Tasks.GenerateEntities"

    @moduledoc false

    @doc \"\"\"
    Returns unicode codepoints for a given HTML entity.
    \"\"\"
    @spec get(binary()) :: list(integer)
    """

    fun_template = fn {key, value} ->
      [
        "def get(",
        inspect(key),
        "), do: ",
        inspect(Map.fetch!(value, "codepoints"), charlists: :as_lists),
        "\n"
      ]
    end

    functions =
      json
      |> Enum.sort_by(fn {key, _value} -> key end)
      |> Enum.map(fun_template)

    bottom = """
      def get(_), do: []
    end
    """

    contents =
      [headers, functions, bottom]
      |> IO.iodata_to_binary()
      |> Code.format_string!()

    File.write!(@destination_module_path, contents)

    Mix.shell().info("Entities module is located in lib/floki/entities/codepoints.ex")
  end
end
