defmodule BerrypodWeb.FaviconControllerTest do
  use BerrypodWeb.ConnCase, async: false

  alias Berrypod.Media

  # Minimal valid PNG (1x1 transparent)
  @test_png <<137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0,
              1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 10, 73, 68, 65, 84, 120, 156, 98, 0, 0,
              0, 2, 0, 1, 226, 33, 188, 51, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130>>

  @test_svg ~s(<svg xmlns="http://www.w3.org/2000/svg"><circle r="10"/></svg>)

  defp create_source_image do
    {:ok, image} =
      Media.upload_image(%{
        image_type: "icon",
        filename: "icon.svg",
        content_type: "image/svg+xml",
        file_size: byte_size(@test_svg),
        data: @test_svg
      })

    image
  end

  defp create_favicon_variants(_context) do
    image = create_source_image()

    {:ok, variants} =
      Media.store_favicon_variants(%{
        source_image_id: image.id,
        png_32: @test_png,
        png_180: @test_png,
        png_192: @test_png,
        png_512: @test_png,
        svg: @test_svg
      })

    %{variants: variants}
  end

  describe "favicon routes with variants" do
    setup [:create_favicon_variants]

    test "serves favicon SVG", %{conn: conn} do
      conn = get(conn, ~p"/favicon.svg")
      assert response_content_type(conn, :xml) =~ "image/svg+xml"
      assert conn.status == 200
      assert conn.resp_body =~ "<svg"
      assert get_resp_header(conn, "cache-control") == ["public, max-age=86400"]
      assert [etag] = get_resp_header(conn, "etag")
      assert etag =~ ~r/^"fav-\d+"$/
    end

    test "serves 32x32 PNG favicon", %{conn: conn} do
      conn = get(conn, ~p"/favicon-32x32.png")
      assert conn.status == 200
      assert response_content_type(conn, :png) =~ "image/png"
      assert <<137, 80, 78, 71, _::binary>> = conn.resp_body
    end

    test "serves apple touch icon", %{conn: conn} do
      conn = get(conn, ~p"/apple-touch-icon.png")
      assert conn.status == 200
      assert response_content_type(conn, :png) =~ "image/png"
    end

    test "serves 192px icon", %{conn: conn} do
      conn = get(conn, ~p"/icon-192.png")
      assert conn.status == 200
      assert response_content_type(conn, :png) =~ "image/png"
    end

    test "serves 512px icon", %{conn: conn} do
      conn = get(conn, ~p"/icon-512.png")
      assert conn.status == 200
      assert response_content_type(conn, :png) =~ "image/png"
    end

    test "returns 304 for matching ETag", %{conn: conn} do
      conn1 = get(conn, ~p"/favicon-32x32.png")
      [etag] = get_resp_header(conn1, "etag")

      conn2 =
        conn
        |> put_req_header("if-none-match", etag)
        |> get(~p"/favicon-32x32.png")

      assert conn2.status == 304
    end
  end

  describe "favicon routes without variants" do
    test "returns 404 for favicon SVG", %{conn: conn} do
      conn = get(conn, ~p"/favicon.svg")
      assert conn.status == 404
    end

    test "returns 404 for PNG variants", %{conn: conn} do
      assert get(conn, ~p"/favicon-32x32.png").status == 404
      assert get(conn, ~p"/apple-touch-icon.png").status == 404
      assert get(conn, ~p"/icon-192.png").status == 404
      assert get(conn, ~p"/icon-512.png").status == 404
    end
  end

  describe "webmanifest" do
    test "returns valid JSON manifest", %{conn: conn} do
      conn = get(conn, ~p"/site.webmanifest")
      assert conn.status == 200
      assert response_content_type(conn, :json) =~ "application/manifest+json"

      manifest = json_response(conn, 200)
      assert manifest["name"] == "Store Name"
      assert manifest["display"] == "minimal-ui"
      assert manifest["start_url"] == "/"
      assert is_binary(manifest["theme_color"])
      assert is_binary(manifest["background_color"])
      assert length(manifest["icons"]) == 2
    end

    test "manifest icons have correct sizes", %{conn: conn} do
      manifest = json_response(get(conn, ~p"/site.webmanifest"), 200)
      icons = manifest["icons"]

      assert Enum.any?(icons, &(&1["sizes"] == "192x192"))
      assert Enum.any?(icons, &(&1["sizes"] == "512x512"))
    end

    test "manifest uses short name from settings", %{conn: conn} do
      manifest = json_response(get(conn, ~p"/site.webmanifest"), 200)
      # Default: truncated site_name (no favicon_short_name set)
      assert is_binary(manifest["short_name"])
      assert String.length(manifest["short_name"]) <= 12
    end
  end
end
