defmodule ToweropsWeb.Plugs.DetectEUUser do
  @moduledoc """
  Detects if a user is from an EU/EEA country that requires GDPR cookie consent.

  Uses local GeoIP database to determine the user's country from their IP address.

  The result is stored in conn.assigns.requires_cookie_consent
  """
  import Plug.Conn

  # EU/EEA country codes that require GDPR cookie consent
  # EU member states + EEA countries (Norway, Iceland, Liechtenstein)
  @eu_eea_countries ~w(
    AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE
    IS NO LI
  )

  # British overseas territories and Crown dependencies also covered by GDPR
  @uk_territories ~w(
    GB GG JE IM GI
  )

  @doc false
  def init(opts), do: opts

  @doc false
  def call(conn, _opts) do
    require Logger

    # Fetch cookies to check for existing consent
    conn = fetch_cookies(conn)
    requires_consent = detect_eu_user(conn)

    # Store in process dictionary so layouts can access it
    Process.put(:requires_cookie_consent, requires_consent)

    conn
    |> put_session(:requires_cookie_consent, requires_consent)
    |> assign(:requires_cookie_consent, requires_consent)
  end

  defp detect_eu_user(conn) do
    # If user has already accepted cookies, don't show banner
    if has_consent_cookie?(conn) do
      false
    else
      # In development (localhost), always show the banner for testing
      hostname = conn.host

      if hostname in ["localhost", "127.0.0.1"] do
        true
      else
        detect_country_from_headers(conn)
      end
    end
  end

  defp has_consent_cookie?(conn) do
    case conn.cookies["cookie_consent"] do
      "accepted" -> true
      _ -> false
    end
  end

  defp detect_country_from_headers(conn) do
    # Get remote IP from connection
    remote_ip = get_remote_ip(conn)

    case Towerops.GeoIP.lookup(remote_ip) do
      country_code when is_binary(country_code) ->
        eu_country?(country_code)

      nil ->
        # No country found - default to showing banner (conservative approach)
        true
    end
  end

  defp get_remote_ip(conn) do
    # Check X-Forwarded-For header first (if behind proxy/load balancer)
    case get_req_header(conn, "x-forwarded-for") do
      [forwarded] ->
        # X-Forwarded-For can contain multiple IPs, take the first (client IP)
        forwarded
        |> String.split(",")
        |> List.first()
        |> String.trim()

      _ ->
        # Fall back to direct connection IP
        case conn.remote_ip do
          {a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}"
          _ -> "0.0.0.0"
        end
    end
  end

  defp eu_country?(country_code) do
    country_code = String.upcase(country_code)
    country_code in @eu_eea_countries or country_code in @uk_territories
  end
end
