defmodule ToweropsWeb.Plugs.DetectEUUserTest do
  use ToweropsWeb.ConnCase, async: true

  alias ToweropsWeb.Plugs.DetectEUUser

  describe "init/1" do
    test "returns options unchanged" do
      assert DetectEUUser.init([]) == []
      assert DetectEUUser.init(some: :option) == [some: :option]
    end
  end

  describe "call/2 - localhost" do
    test "always requires consent for localhost" do
      conn =
        build_conn()
        |> Map.put(:host, "localhost")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      assert conn.assigns.requires_cookie_consent == true
      assert get_session(conn, :requires_cookie_consent) == true
      assert Process.get(:requires_cookie_consent) == true
    end

    test "always requires consent for 127.0.0.1" do
      conn =
        build_conn()
        |> Map.put(:host, "127.0.0.1")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      assert conn.assigns.requires_cookie_consent == true
      assert get_session(conn, :requires_cookie_consent) == true
    end
  end

  describe "call/2 - non-localhost (GeoIP integration)" do
    test "requires consent when GeoIP returns nil (conservative approach)" do
      # GeoIP.lookup will return nil in test environment (no data)
      # This tests the conservative default behavior
      conn =
        build_conn()
        |> Map.put(:host, "example.com")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Should default to requiring consent when country cannot be determined
      assert conn.assigns.requires_cookie_consent == true
    end
  end

  describe "call/2 - stores in multiple locations" do
    test "stores consent requirement in session, assigns, and process dictionary" do
      conn =
        build_conn()
        |> Map.put(:host, "localhost")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Check all three storage locations
      assert conn.assigns.requires_cookie_consent == true
      assert get_session(conn, :requires_cookie_consent) == true
      assert Process.get(:requires_cookie_consent) == true
    end
  end

  describe "call/2 - X-Forwarded-For header" do
    test "processes X-Forwarded-For header when present" do
      # Just verify the plug doesn't crash with X-Forwarded-For header
      conn =
        build_conn()
        |> Map.put(:host, "example.com")
        |> put_req_header("x-forwarded-for", "203.0.113.195")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # In test env, GeoIP returns nil, so conservative default is true
      assert conn.assigns.requires_cookie_consent == true
    end

    test "handles comma-separated X-Forwarded-For" do
      # Verify the plug handles multiple IPs without crashing
      conn =
        build_conn()
        |> Map.put(:host, "example.com")
        |> put_req_header("x-forwarded-for", "203.0.113.195, 10.0.0.1, 192.168.1.1")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      assert conn.assigns.requires_cookie_consent == true
    end
  end

  describe "call/2 - cookie consent check" do
    test "does not require consent when cookie_consent=accepted cookie exists" do
      conn =
        build_conn()
        |> Map.put(:host, "localhost")
        |> put_req_cookie("cookie_consent", "accepted")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Should not require consent even though localhost normally would
      assert conn.assigns.requires_cookie_consent == false
      assert get_session(conn, :requires_cookie_consent) == false
      assert Process.get(:requires_cookie_consent) == false
    end

    test "requires consent when cookie_consent cookie is missing" do
      conn =
        build_conn()
        |> Map.put(:host, "localhost")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Should require consent (normal localhost behavior)
      assert conn.assigns.requires_cookie_consent == true
      assert get_session(conn, :requires_cookie_consent) == true
      assert Process.get(:requires_cookie_consent) == true
    end

    test "requires consent when cookie_consent cookie has wrong value" do
      conn =
        build_conn()
        |> Map.put(:host, "localhost")
        |> put_req_cookie("cookie_consent", "rejected")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Should require consent (cookie value is not "accepted")
      assert conn.assigns.requires_cookie_consent == true
      assert get_session(conn, :requires_cookie_consent) == true
      assert Process.get(:requires_cookie_consent) == true
    end

    test "does not require consent for non-localhost with accepted cookie" do
      conn =
        build_conn()
        |> Map.put(:host, "example.com")
        |> put_req_cookie("cookie_consent", "accepted")
        |> Plug.Test.init_test_session(%{})
        |> DetectEUUser.call([])

      # Should not require consent even though GeoIP would return nil (conservative default)
      assert conn.assigns.requires_cookie_consent == false
      assert get_session(conn, :requires_cookie_consent) == false
      assert Process.get(:requires_cookie_consent) == false
    end
  end
end
