defmodule PhilomenaWeb.ScraperPlug do
  @filename_regex ~r/filename="([^"]+)"/

  @spec init(keyword()) :: keyword()
  def init(opts) do
    opts
  end

  @spec call(Plug.Conn.t(), keyword()) :: Plug.Conn.t()
  def call(conn, opts) do
    params_name = Keyword.get(opts, :params_name, "image")
    params_key = Keyword.get(opts, :params_key, "image")

    case conn.params do
      %{^params_name => %{^params_key => %Plug.Upload{}}} ->
        conn

      %{"scraper_cache" => url} when not is_nil(url) and url != "" ->
        url
        |> PhilomenaProxy.Http.get()
        |> maybe_fixup_params(url, opts, conn)

      _ ->
        conn
    end
  end

  # Writing the tempfile doesn't allow traversal
  # sobelow_skip ["Traversal.FileModule"]
  defp maybe_fixup_params({:ok, %{status: 200} = resp}, url, opts, conn) do
    params_name = Keyword.get(opts, :params_name, "image")
    params_key = Keyword.get(opts, :params_key, "image")
    name = extract_filename(url, resp.headers)
    file = Plug.Upload.random_file!(UUID.uuid1())

    File.write!(file, resp.body)

    fake_upload = %Plug.Upload{
      path: file,
      content_type: "application/octet-stream",
      filename: name
    }

    put_in(conn.params[params_name][params_key], fake_upload)
  end

  defp maybe_fixup_params(_response, _url, _opts, conn), do: conn

  defp extract_filename(url, headers) do
    name =
      with [value | _] <- headers["content-disposition"],
           [name] <- Regex.run(@filename_regex, value, capture: :all_but_first) do
        name
      else
        _ ->
          Path.basename(url)
      end

    String.slice(name, 0, 127)
  end
end