defmodule BDS.Rendering.FileSystem do
  @moduledoc false

  defstruct [:root_paths]

  def new(root_paths) when is_list(root_paths) do
    %__MODULE__{root_paths: Enum.uniq(root_paths)}
  end

  def new(root_path) when is_binary(root_path) do
    new([root_path])
  end

  def full_path(%__MODULE__{root_paths: root_paths}, template_path) do
    normalized_path = to_string(template_path)

    cond do
      normalized_path == "" ->
        raise Liquex.Error, message: "Illegal template path '#{template_path}'"

      Path.type(normalized_path) == :absolute ->
        raise Liquex.Error, message: "Illegal template path '#{template_path}'"

      String.contains?(normalized_path, "..") ->
        raise Liquex.Error, message: "Illegal template path '#{template_path}'"

      true ->
        root_paths
        |> Enum.map(&Path.expand(Path.join(&1, normalized_path <> ".liquid")))
        |> Enum.find(&File.regular?/1)
        |> case do
          nil ->
            Path.expand(Path.join(List.first(root_paths) || ".", normalized_path <> ".liquid"))

          path ->
            path
        end
    end
  end
end

defimpl Liquex.FileSystem, for: BDS.Rendering.FileSystem do
  def read_template_file(file_system, template_path) do
    file_system
    |> BDS.Rendering.FileSystem.full_path(template_path)
    |> File.read()
    |> case do
      {:ok, contents} -> contents
      _error -> raise Liquex.Error, message: "No such template '#{template_path}'"
    end
  end
end
