defmodule TheMovieDB.Gateway do
  require Logger

  def do_request(path, parameters \\ []) do
    method = :get
    query_params = :hackney_url.qs(Enum.concat([{"api_key", api_key}], parameters))
    url = :hackney_url.make_url(api_url, path, query_params)
    headers = []
    payload = <<>>
    options = []

    Logger.debug("TheMovieDB: #{method} : #{inspect(url)}")

    with {:ok, 200, _headers, clientref} <- :hackney.request(method, url, headers, payload, options),
         {:ok, response_string} <- :hackney.body(clientref),
         {:ok, json} <- Poison.decode(response_string),
         map = %{} <- TheMovieDB.Util.keys_to_atoms(json) do
      {:ok, map}
    else
      err -> {:error, err}
    end
  end

  def api_key do
    System.get_env("TMDB_KEY")
  end

  def api_url do
    Application.get_env(:themoviedb, :api_path)
  end
end


###############################################################################################################

defmodule TheMovieDB.Test.Gateway do
  use ExUnit.Case

  setup do
    bypass = Bypass.open()
    {:ok, bypass: bypass}
  end

  test "Sucessful request", %{bypass: bypass} do
    Bypass.expect(bypass, fn conn ->
      Plug.Conn.resp(conn, 200, ~s({"pong": 5}))
    end)

    # Set the temporary endpoint now.
    bypass_endpoint = "http://localhost:#{bypass.port}/"
    Application.put_env(:themoviedb, :api_path, bypass_endpoint)

    # Should just come through in a map.
    assert {:ok, %{:pong => 5}} = TheMovieDB.Gateway.do_request("/")
  end

  test "Invalid API Key", %{bypass: bypass} do
    Bypass.expect(bypass, fn conn ->
      Plug.Conn.resp(
        conn,
        401,
        ~s({"status_code":7,"status_message":"Invalid API key: You must be granted a valid key.","success":false})
      )
    end)

    # Set the temporary endpoint now.
    bypass_endpoint = "http://localhost:#{bypass.port}/"
    Application.put_env(:themoviedb, :api_path, bypass_endpoint)

    # Assert expected response.
    assert {:error, {:ok, 401, _, _}} = TheMovieDB.Gateway.do_request("/")
  end

end


###############################################################################################################


defmodule TheMovieDB.Test.Api.Movies do
  use ExUnit.Case

  setup do
    bypass = Bypass.open()
    {:ok, bypass: bypass}
  end

  ##############################################################################
  test "Get details of movie.", %{bypass: bypass} do
    Bypass.expect(bypass, fn conn ->
      Plug.Conn.resp(
        conn,
        200,
        ~s({"adult":false,"backdrop_path":"/8HqSxB9VLJkbRXRdlocbLq9wxwY.jpg","belongs_to_collection":{"id":141290,"name":"The Lord of the Rings Animated Collection","poster_path":"/pQuazFOlGRdn2Lb3oWFJYPeASOc.jpg","backdrop_path":"/uUG532EWfyhtKDzsA0sLb1PsHhL.jpg"},"budget":4000000,"genres":[{"id":12,"name":"Adventure"},{"id":16,"name":"Animation"},{"id":18,"name":"Drama"},{"id":14,"name":"Fantasy"},{"id":10751,"name":"Family"}],"homepage":"","id":123,"imdb_id":"tt0077869","original_language":"en","original_title":"The Lord of the Rings","overview":"The Fellowship of the Ring embark on a journey to destroy the One Ring and end Sauron's reign over Middle-earth.","popularity":12.143,"poster_path":"/1l3WpoF7TX9pOprX4XepCXjQXUV.jpg","production_companies":[{"id":60,"logo_path":"/oJXpAs4I3W46e4dkaOEzCa4yBko.png","name":"United Artists","origin_country":"US"},{"id":286,"logo_path":null,"name":"Fantasy Films","origin_country":""}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1978-11-15","revenue":30471420,"runtime":132,"spoken_languages":[{"iso_639_1":"en","name":"English"}],"status":"Released","tagline":"Fantasy...beyond your imagination","title":"The Lord of the Rings","video":false,"vote_average":6.5,"vote_count":413})
      )
    end)

    # Set the temporary endpoint now.
    bypass_endpoint = "http://localhost:#{bypass.port}/"
    Application.put_env(:themoviedb, :api_path, bypass_endpoint)

    # Should just come through in a map.
    assert %Movie{
             adult: false,
             backdrop_path: "/8HqSxB9VLJkbRXRdlocbLq9wxwY.jpg",
             belongs_to_collection: %{
               backdrop_path: "/uUG532EWfyhtKDzsA0sLb1PsHhL.jpg",
               id: 141_290,
               name: "The Lord of the Rings Animated Collection",
               poster_path: "/pQuazFOlGRdn2Lb3oWFJYPeASOc.jpg"
             },
             budget: 4_000_000,
             genres: [
               %{id: 12, name: "Adventure"},
               %{id: 16, name: "Animation"},
               %{id: 18, name: "Drama"},
               %{id: 14, name: "Fantasy"},
               %{id: 10751, name: "Family"}
             ],
             homepage: "",
             id: 123,
             imdb_id: "tt0077869",
             original_language: "en",
             original_title: "The Lord of the Rings",
             overview:
               "The Fellowship of the Ring embark on a journey to destroy the One Ring and end Sauron's reign over Middle-earth.",
             popularity: 12.143,
             poster_path: "/1l3WpoF7TX9pOprX4XepCXjQXUV.jpg",
             release_date: "1978-11-15",
             runtime: 132,
             spoken_languages: [%{iso_639_1: "en", name: "English"}],
             status: "Released",
             tagline: "Fantasy...beyond your imagination",
             title: "The Lord of the Rings",
             video: false,
             vote_average: 6.5,
             vote_count: 413
           } = TheMovieDB.Movies.get_details(123)
  end

  ##############################################################################
  test "Get details of invalid movieid.", %{bypass: bypass} do
    Bypass.expect(bypass, fn conn ->
      Plug.Conn.resp(
        conn,
        404,
        ~s({"status_code":34,"status_message":"The resource you requested could not be found."})
      )
    end)

    # Set the temporary endpoint now.
    bypass_endpoint = "http://localhost:#{bypass.port}/"
    Application.put_env(:themoviedb, :api_path, bypass_endpoint)

    # Should just come through in a map.
    assert {:error, "Error getting details from the API."} = TheMovieDB.Movies.get_details(123)
  end

  ##############################################################################
  test "Get details of a valid movieid but with wrong API key.", %{bypass: bypass} do
    Bypass.expect(bypass, fn conn ->
      Plug.Conn.resp(
        conn,
        401,
        ~s({"status_code":7,"status_message":"Invalid API key: You must be granted a valid key.","success":false})
      )
    end)

    # Set the temporary endpoint now.
    bypass_endpoint = "http://localhost:#{bypass.port}/"
    Application.put_env(:themoviedb, :api_path, bypass_endpoint)

    # Should just come through in a map.
    assert {:error, "Error getting details from the API."} = TheMovieDB.Movies.get_details(123)
  end
end