defmodule WhoNeedHelpWeb.PageControllerTest do
  use WhoNeedHelpWeb.ConnCase

  test "GET /", %{conn: conn} do
    conn = get(conn, ~p"/")
    html = html_response(conn, 200)
    document = LazyHTML.from_document(html)
    [content_security_policy] = get_resp_header(conn, "content-security-policy")

    assert html =~ "Help can be closer than you think."
    assert content_security_policy =~ "default-src 'self'"
    assert content_security_policy =~ "script-src 'self'"
    refute content_security_policy =~ "script-src 'self' 'unsafe-inline'"
    assert content_security_policy =~ "frame-ancestors 'none'"
    assert content_security_policy =~ "https://tile.openstreetmap.org"
    assert content_security_policy =~ "ws://www.example.com"
    refute content_security_policy =~ "wss://www.example.com"

    assert get_resp_header(conn, "permissions-policy") == [
             "geolocation=(self), camera=(), microphone=(), payment=(), usb=()"
           ]

    assert html =~
             ~s(data-map-tile-url="https://tile.openstreetmap.org/{z}/{x}/{y}.png")

    assert Enum.count(LazyHTML.query(document, "body > header")) == 1

    assert Enum.count(LazyHTML.query(document, "header nav[aria-label='Primary navigation']")) ==
             1

    assert Enum.empty?(LazyHTML.query(document, "body > nav[aria-label='Account and language']"))

    assert Enum.count(LazyHTML.query(document, "header img[src='/images/logo.svg'][alt='']")) == 1

    assert Enum.count(LazyHTML.query(document, "head link[rel='icon'][href='/images/logo.svg']")) ==
             1

    assert Enum.count(
             LazyHTML.query(document, "head link[rel='apple-touch-icon'][sizes='180x180']")
           ) == 1
  end

  test "HTTPS content security policy permits only secure WebSockets", %{conn: conn} do
    conn =
      conn
      |> Map.put(:scheme, :https)
      |> Map.put(:host, "help.example")
      |> Map.put(:port, 443)
      |> WhoNeedHelpWeb.SecurityHeaders.put_content_security_policy([])

    [content_security_policy] = get_resp_header(conn, "content-security-policy")

    assert content_security_policy =~ "wss://help.example"
    refute content_security_policy =~ "ws://help.example"
  end

  test "Phoenix logs filter authentication and handover secrets" do
    assert Phoenix.Logger.filter_values(%{
             "password" => "not-logged",
             "_csrf_token" => "not-logged",
             "token" => "not-logged",
             "handover" => %{"code" => "123456"},
             "email" => "visible@example.test"
           }) == %{
             "password" => "[FILTERED]",
             "_csrf_token" => "[FILTERED]",
             "token" => "[FILTERED]",
             "handover" => %{"code" => "[FILTERED]"},
             "email" => "visible@example.test"
           }
  end

  test "GET / selects Russian locale", %{conn: conn} do
    conn = get(conn, ~p"/?locale=ru")
    assert html_response(conn, 200) =~ "Помощь может быть ближе, чем кажется."
  end

  test "health endpoints expose status without internal node names", %{conn: conn} do
    assert %{"status" => "ok"} =
             conn
             |> get(~p"/healthz/live")
             |> json_response(200)

    assert %{"status" => "ready"} =
             conn
             |> recycle()
             |> get(~p"/healthz/ready")
             |> json_response(200)
  end

  test "GET /safety selects Ukrainian locale and keeps it in the session", %{conn: conn} do
    conn = get(conn, ~p"/safety?locale=uk")
    assert html_response(conn, 200) =~ "Правила безпеки"

    conn = get(conn, ~p"/")
    assert html_response(conn, 200) =~ "Допомога може бути ближче, ніж здається."
  end

  test "GET /safety", %{conn: conn} do
    conn = get(conn, ~p"/safety")
    assert html_response(conn, 200) =~ "Safety rules"
    assert html_response(conn, 200) =~ "Not for emergencies"
  end

  test "GET /privacy publishes the Google data disclosure and user controls", %{conn: conn} do
    conn = get(conn, ~p"/privacy")
    html = html_response(conn, 200)

    assert html =~ "Privacy Policy"
    assert html =~ "Google sign-in data"
    assert html =~ "does not persist Google access tokens or ID tokens"
    assert html =~ "Privacy Policy · Who Need Help"
    assert html =~ ~s(name="description")
    assert html =~ "How Who Need Help processes account, Google sign-in, location"
    assert html =~ ~s(href="/account/delete")
    assert html =~ ~s(href="/support")
  end

  test "GET /terms links the safety and privacy documents", %{conn: conn} do
    conn = get(conn, ~p"/terms")
    html = html_response(conn, 200)

    assert html =~ "Terms of Service"
    assert html =~ "Terms of Service · Who Need Help"
    assert html =~ "conditions for using Who Need Help"
    assert html =~ ~s(href="/safety")
    assert html =~ ~s(href="/privacy")
    assert html =~ ~s(href="/support")
  end

  test "GET /manifest.webmanifest", %{conn: conn} do
    conn = get(conn, "/manifest.webmanifest")
    manifest = conn |> response(200) |> JSON.decode!()

    assert manifest["short_name"] == "Who Need Help"
    assert manifest["id"] == "/"

    assert Enum.any?(manifest["icons"], fn icon ->
             icon["sizes"] == "192x192" and icon["purpose"] == "any"
           end)

    assert Enum.any?(manifest["icons"], fn icon ->
             icon["sizes"] == "512x512" and icon["purpose"] == "any"
           end)

    assert Enum.any?(manifest["icons"], fn icon ->
             icon["sizes"] == "1024x1024" and icon["purpose"] == "maskable"
           end)

    assert Enum.any?(manifest["icons"], fn icon ->
             icon["type"] == "image/svg+xml" and icon["purpose"] == "monochrome"
           end)
  end

  test "GET /sw.js", %{conn: conn} do
    conn = get(conn, "/sw.js")
    body = response(conn, 200)

    assert body =~ ~s(const CACHE_PREFIX = "who-need-help-static-")
    assert body =~ ~s(const CACHE = `${CACHE_PREFIX}v4`)
    assert body =~ ~s(const OFFLINE_URL = "/offline.html")
    assert body =~ ~s(event.request.mode === "navigate")
    assert body =~ ~S|key.startsWith(CACHE_PREFIX) && key !== CACHE|
    assert body =~ "self.skipWaiting()"
    assert body =~ "self.clients.claim()"
  end

  test "GET /offline.html", %{conn: conn} do
    conn = get(conn, "/offline.html")
    html = html_response(conn, 200)
    document = LazyHTML.from_document(html)

    assert Enum.count(LazyHTML.query(document, "main[aria-labelledby='offline-title']")) == 1
    assert Enum.count(LazyHTML.query(document, "img[src='/images/logo.svg'][alt='']")) == 1
    assert html =~ "You're offline"
    assert html =~ "Try again"
  end

  test "brand raster fallbacks are served", %{conn: conn} do
    for path <- [
          "/images/favicon-48.png",
          "/images/pwa-192.png",
          "/images/pwa-512.png",
          "/images/pwa-maskable-512.png",
          "/images/pwa-maskable-1024.png",
          "/images/apple-touch-icon.png"
        ] do
      response = conn |> recycle() |> get(path)

      assert response.status == 200
      assert get_resp_header(response, "content-type") == ["image/png"]
    end
  end
end
